質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

Q&A

1回答

5780閲覧

HTTPサーバでのPOSTが来た際の処理

Subaru

総合スコア15

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

0グッド

1クリップ

投稿2015/05/25 06:55

POSTリクエストが来た際に標準入力からcgiにパラメータを渡すということはわかりますが
具体的にどのように処理をしていいのかわかりません。教えてください
また、今回のプログラムはGET、POSTの両方でcgiにパラメータを渡して処理できるHTTPサーバを目指しています。プログラムに不備があれば指摘してくれればと思います。

lang

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <unistd.h> 5#include <sys/socket.h> 6#include <sys/fcntl.h> 7#include <sys/wait.h> 8#include <sys/types.h> 9#include <arpa/inet.h> 10 11#define MAXPENDING 5 12 13void DieWithError(char *errorMessage); 14int CreateTCPServerSocket(unsigned short port); 15int AcceptTCPConnection(int servSock); 16int sendMessage(int fd, char *msg); 17void sendHeader(int clntSock); 18int http(int clntSock); 19void cgiMethod(int clntSock, char *uri_file, char *value); 20 21 22/* ========================== */ 23 24int main( int argc,char *argv[] ) 25{ 26 int servSock; 27 int clntSock; 28 unsigned short ServPort; 29 30 int clnt_len; 31 int rc = 0; 32 pid_t processID; 33 unsigned int ProcessCount = 0; 34 35 struct sockaddr_in serv_addr; 36 struct sockaddr_in clnt_addr; 37 38 // serverPort 39 if( argc != 2 ) 40 { 41 fprintf(stderr, "Usage: %s <server port>\n",argv[0]); 42 exit(1); 43 } 44 45 ServPort = atoi(argv[1]); 46 servSock = CreateTCPServerSocket(ServPort); 47 48 while(1) 49 { 50 clntSock = AcceptTCPConnection(servSock); 51 52 if ( (processID = fork()) < 0 ) 53 { 54 fprintf(stderr, "error: fork() failed"); 55 return 1; 56 } 57 else if ( processID == 0 ) 58 { 59 close(servSock); 60 http(clntSock); 61 return 0; 62 } 63 64 // 親プロセス 65 printf("with process1: %d\n", (int) processID); 66 close(clntSock); 67 ProcessCount++; 68 69 //プロセスの回収 70 while( ProcessCount ) 71 { 72 processID = waitpid((pid_t) -1, NULL, WNOHANG); 73 if(processID < 0) 74 { 75 fprintf(stderr, "error: waitpid() failed"); 76 break; 77 } 78 else if(processID == 0) 79 break; 80 else 81 ProcessCount--; 82 } 83 } 84} 85 86/* ========================== */ 87 88 89/* errerMessage */ 90void DieWithError(char *errorMessage){ 91 perror(errorMessage); 92 exit(1); 93} 94 95/* soket,bind,listen */ 96int CreateTCPServerSocket(unsigned short port){ 97 98 int sock; 99 struct sockaddr_in echoServAddr; 100 101 if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 102 DieWithError("socket() failed"); 103 104 // 構造体の初期化 105 memset(&echoServAddr, 0, sizeof(echoServAddr)); 106 107 echoServAddr.sin_family = AF_INET; 108 echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); 109 echoServAddr.sin_port = htons(port); 110 111 // localAddrへbind 112 if(bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) 113 DieWithError("bind() failed"); 114 115 if(listen(sock, MAXPENDING) < 0) 116 DieWithError("listen() failed"); 117 118 return sock; 119} 120 121/* Accept */ 122int AcceptTCPConnection(int servSock){ 123 int clntSock; 124 struct sockaddr_in echoClntAddr; 125 unsigned int clntLen; 126 127 clntLen = sizeof(echoClntAddr); 128 129 if((clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, &clntLen)) < 0) 130 DieWithError("accept() failed"); 131 132 printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr)); 133 134 return clntSock; 135} 136 137void sendHeader( int clntSock ) { 138 sendMessage( clntSock, "HTTP/1.1 200 OK\r\n" ); 139 sendMessage( clntSock, "Content-type: text/html; charset=UTF-8\r\n" ); 140 sendMessage( clntSock, "\r\n" ); 141} 142 143int sendMessage(int fd, char *msg){ 144 int msg_len; 145 msg_len = strlen(msg); 146 147 if ( write(fd, msg, msg_len) != msg_len ) 148 { 149 fprintf(stderr, "error: writing."); 150 } 151 return msg_len; 152} 153 154int http(int clntSock){ 155 int len; 156 int read_fd; 157 char buf[1024]; 158 pid_t processID; 159 unsigned int ProcessCount = 0; 160 161 char method_name[16]; 162 char uri_addr[256]; 163 char http_ver[64]; 164 char *uri_file; 165 char *value; 166 167 if(read(clntSock, buf, 1024) <= 0 ) 168 { 169 fprintf(stderr, "error: reading a request.\n"); 170 exit(1); 171 } 172 173 sscanf(buf, "%s %s %s", method_name, uri_addr, http_ver); 174 //printf("%s %s %s\n", method_name, uri_addr, http_ver); 175 176 uri_file = uri_addr + 1; 177 178 if (strcmp(method_name, "GET") == 0) 179 { 180 if (strstr(uri_addr, ".cgi") != NULL) 181 { 182 uri_file = strtok(uri_file, "?"); 183 value = strtok(NULL, ""); 184 cgiMethod(clntSock, uri_file, value); 185 close(clntSock); 186 } 187 else{ 188 if ((read_fd = open(uri_file, O_RDONLY, 0666)) < 0) 189 { 190 sendMessage(clntSock, "404 Not Found"); 191 return 1; 192 } 193 194 sendHeader(clntSock); 195 196 while ((len = read(read_fd, buf, 1024)) > 0) 197 { 198 if (write(clntSock, buf, len) != len) 199 { 200 fprintf(stderr, "error: writing a response.\n"); 201 break; 202 } 203 } 204 close(read_fd); 205 } 206 } 207 else if ( strcmp(method_name, "POST" ) == 0) { 208 209 // 210 //ここをどのように書くかわからない 211 // 212 213 close(clntSock); 214 } 215 else { 216 sendMessage(clntSock, "501 Not Implemented"); 217 exit(1); 218 } 219} 220 221void cgiMethod(int clntSock, char *uri_file, char *value){ 222 223 pid_t processID; 224 unsigned int ProcessCount = 0; 225 int fd[2]; 226 int len; 227 char buf[1024]; 228 229 230 pipe(fd); 231 232 if((processID = fork()) < 0) 233 { 234 fprintf(stderr, "error: fork() failed"); 235 exit(1); 236 } 237 else if(processID == 0) 238 { 239 close(fd[0]); 240 dup2(fd[1], 1); 241 242 setenv("QUERY_STRING" ,value, 1); 243 244 if (execl(uri_file, "", NULL) < 0) 245 { 246 fprintf(stderr, "error: execl() failed\n"); 247 exit(1); 248 } 249 250 close(clntSock); 251 ProcessCount++; 252 exit(0); 253 } 254 255 close(fd[1]); 256 257 sendHeader(clntSock); 258 while((len = read(fd[0], buf, sizeof(buf))) > 0) 259 { 260 if(write(clntSock, buf, len) != len) 261 { 262 fprintf(stderr, "error: writing a response.\n"); 263 break; 264 } 265 } 266 267 // プロセスの回収 268 printf("with process2: %d\n", (int) processID); 269 270 while(ProcessCount) 271 { 272 processID = waitpid((pid_t) -1, NULL, WNOHANG); 273 if(processID < 0) 274 { 275 fprintf(stderr, "error: waitpid() failed"); 276 break; 277 } 278 else if(processID == 0) 279 break; 280 else 281 ProcessCount--; 282 } 283 284 close(fd[0]); 285} 286 287 288 289

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

clntSockからreadしたものを、先頭からきちんとHTTPプロトコルに従って解析して、リクエストボディ部分をPOSTデータとします。

あと、アドバイスとしては、read(clntSock,buf,1024)するのでなく、fdopenを使って、

lang

1FILE *fp; 2~~~ 3if(!(fp=fdopen(clntSock,"r"))){ 4 エラー処理 5} 6if(!fgets(buf,1024,fp)){ 7 エラー処理 8}

のようにfgetsで行単位で読んだ方が、リクエストやリクエストヘッダの解析をするときに楽です。
空行の後ろが、ボディ。
ボディを読むときは、fgetsでなくfreadで。

投稿2015/05/25 15:51

otn

総合スコア84505

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問