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

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

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

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

ソケット

TCP/IPにおいて、IPアドレスとサブアドレスであるポート番号を組み合わせたネットワークアドレスのことを呼びます。また、ソフトウェアアプリケーションにおいて、TCP/IP通信を行う為の仮想的なインターフェースという意味もある。

Q&A

1回答

272閲覧

C言語でのHTTPサーバーでPOSTリクエストのファイルアップロードが正しく処理されない

shigureair

総合スコア0

C

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

ソケット

TCP/IPにおいて、IPアドレスとサブアドレスであるポート番号を組み合わせたネットワークアドレスのことを呼びます。また、ソフトウェアアプリケーションにおいて、TCP/IP通信を行う為の仮想的なインターフェースという意味もある。

1グッド

0クリップ

投稿2024/06/24 09:20

実現したいこと

HTTPサーバーが正しくファイルアップロードを処理し、画像ファイルをサーバーに保存するようにする。

発生している問題・分からないこと

HTTPサーバーをC言語で実装しています。POSTリクエストを処理し、クライアントから送信されたファイルをサーバーに保存したいのですが、リクエストボディの解析が正しく行われず、ファイルデータが正しく保存されません。現在のコードでは、POSTリクエストのヘッダーは正しく受信されていますが、ファイルデータの部分がうまく処理されていない状態です。
何か解決法をご教示いただけますと幸いです。

該当のソースコード

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <unistd.h> 5#include <sys/socket.h> 6#include <netinet/in.h> 7#include <arpa/inet.h> 8#include <fcntl.h> 9#include <errno.h> 10#include <sys/stat.h> 11#include <sys/types.h> 12#include <sys/wait.h> 13 14#define PORT 8080 15#define BUFSIZE 8192 16 17void error(const char *msg) { 18 perror(msg); 19 exit(1); 20} 21 22void handle_request(int newsockfd) { 23 char buffer[BUFSIZE]; 24 int n; 25 char boundary[256]; 26 27 // Read the initial request into the buffer 28 n = read(newsockfd, buffer, BUFSIZE - 1); 29 if (n < 0) error("ERROR reading from socket"); 30 buffer[n] = 0; 31 32 printf("Here is the message: %s\n", buffer); 33 34 if (strncmp(buffer, "GET ", 4) == 0) { 35 // Handle GET request 36 char *filepath = strtok(buffer + 4, " "); 37 if (strcmp(filepath, "/") == 0) { 38 filepath = "/index.html"; 39 } 40 41 char fullpath[BUFSIZE] = "."; 42 strncat(fullpath, filepath, BUFSIZE - strlen(fullpath) - 1); 43 44 int filefd = open(fullpath, O_RDONLY); 45 if (filefd < 0) { 46 char *not_found = "HTTP/1.1 404 Not Found\r\nContent-Length: 13\r\n\r\n404 Not Found"; 47 write(newsockfd, not_found, strlen(not_found)); 48 } else { 49 char response[BUFSIZE]; 50 sprintf(response, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"); 51 write(newsockfd, response, strlen(response)); 52 53 while ((n = read(filefd, buffer, BUFSIZE)) > 0) { 54 write(newsockfd, buffer, n); 55 } 56 close(filefd); 57 } 58 } else if (strncmp(buffer, "POST ", 5) == 0) { 59 // Handle POST request 60 char *content_length_str = strstr(buffer, "Content-Length: "); 61 int content_length = 0; 62 if (content_length_str) { 63 sscanf(content_length_str, "Content-Length: %d", &content_length); 64 } 65 66 char *content_type_str = strstr(buffer, "Content-Type: multipart/form-data; boundary="); 67 if (content_type_str) { 68 sscanf(content_type_str, "Content-Type: multipart/form-data; boundary=%s", boundary); 69 } 70 71 // Read the remaining data of the request 72 if (n < content_length) { 73 int remaining = content_length - n; 74 char *full_request = malloc(content_length + 1); 75 memcpy(full_request, buffer, n); 76 int read_bytes = read(newsockfd, full_request + n, remaining); 77 if (read_bytes < 0) { 78 error("ERROR reading remaining bytes from socket"); 79 } 80 full_request[content_length] = 0; 81 strcpy(buffer, full_request); 82 free(full_request); 83 } 84 85 char *part_start = strstr(buffer, boundary); 86 if (part_start) { 87 part_start += strlen(boundary) + 2; // Skip boundary and \r\n 88 89 while (part_start && *part_start != '-' && *part_start != 0) { 90 char *header_end = strstr(part_start, "\r\n\r\n"); 91 if (header_end) { 92 header_end += 4; // Skip past \r\n\r\n 93 94 char *part_end = strstr(header_end, boundary); 95 if (part_end) { 96 part_end -= 2; // Exclude trailing \r\n 97 98 // Check for Content-Disposition header with filename 99 char *content_disposition = strstr(part_start, "Content-Disposition: "); 100 if (content_disposition && strstr(content_disposition, "filename=")) { 101 size_t data_length = part_end - header_end; 102 if (data_length > 0) { 103 FILE *file = fopen("upload.jpg", "wb"); 104 if (file) { 105 fwrite(header_end, 1, data_length, file); 106 fclose(file); 107 108 char *ok_response = "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nOK"; 109 write(newsockfd, ok_response, strlen(ok_response)); 110 } else { 111 char *internal_error = "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 21\r\n\r\n500 Internal Server Error"; 112 write(newsockfd, internal_error, strlen(internal_error)); 113 } 114 } else { 115 char *bad_request = "HTTP/1.1 400 Bad Request\r\nContent-Length: 27\r\n\r\n400 Bad Request: No file data"; 116 write(newsockfd, bad_request, strlen(bad_request)); 117 } 118 } 119 120 part_start = part_end + strlen(boundary) + 2; // Skip past boundary and \r\n 121 } else { 122 break; 123 } 124 } else { 125 break; 126 } 127 } 128 } else { 129 char *bad_request = "HTTP/1.1 400 Bad Request\r\nContent-Length: 15\r\n\r\n400 Bad Request"; 130 write(newsockfd, bad_request, strlen(bad_request)); 131 } 132 } else { 133 char *bad_request = "HTTP/1.1 400 Bad Request\r\nContent-Length: 15\r\n\r\n400 Bad Request"; 134 write(newsockfd, bad_request, strlen(bad_request)); 135 } 136} 137 138int main() { 139 int server_fd, new_socket; 140 struct sockaddr_in address; 141 int addrlen = sizeof(address); 142 143 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 144 perror("Socket creation failed"); 145 exit(EXIT_FAILURE); 146 } 147 148 address.sin_family = AF_INET; 149 address.sin_addr.s_addr = INADDR_ANY; 150 address.sin_port = htons(PORT); 151 152 if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { 153 perror("Bind failed"); 154 close(server_fd); 155 exit(EXIT_FAILURE); 156 } 157 158 if (listen(server_fd, 10) < 0) { 159 perror("Listen failed"); 160 close(server_fd); 161 exit(EXIT_FAILURE); 162 } 163 164 printf("Server is listening on port 8080\n"); 165 166 while (1) { 167 printf("Waiting for connections...\n"); 168 169 if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) { 170 perror("Accept failed"); 171 continue; 172 } 173 174 pid_t pid = fork(); 175 if (pid < 0) { 176 perror("Fork failed"); 177 close(new_socket); 178 continue; 179 } 180 181 if (pid == 0) { 182 close(server_fd); 183 handle_request(new_socket); 184 exit(0); 185 } else { 186 close(new_socket); 187 waitpid(-1, NULL, WNOHANG); // Prevent zombie processes 188 } 189 } 190 191 close(server_fd); 192 return 0; 193} 194

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

POSTリクエストの読み込み処理とMultipart/form-dataのバウンダリの解析処理を追加しましたが、ファイルデータの部分がうまく処理されません。

補足

FW/ツールのバージョンや、補足事項があれば入力してください

開発環境:MacOS 10.15.7
コンパイラ:gcc version 10.2.0
クライアント:Google Chrome 126.0.0.0

tatsu99👍を押しています

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

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

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

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

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

jimbe

2024/06/24 10:06

どのような http 電文を受けた時にどの部分でどのような動作になっているのかを調べているでしょうか。 ただ「コードを書いたけど動かないから教えて」だと、丸投げになります。 >ファイルデータの部分がうまく処理されていない のはなぜ分かったのか、そして具体的にご提示のコードのどの行でどのような変数がどうなるはずがどうなっているので「うまく処理されない」のか…までは追えていますか?
otn

2024/06/24 10:47

「うまく処理されません。」は、主観表現で、情報量ゼロなので、 具体的・客観的な観測事実を書きましょう。 リクエストヘッダ全部、リクエストボディー全部と、処理結果の客観的な記述。 本物のjpgファイルだと検証が面倒なので、デバッグ時はテキストファイルとか、0x00 0x01 0x02 ~~ 0xFF のような簡明なバイナリーファイルが良いと思います。
guest

回答1

0

パッと見ですが、 content-length の扱いを間違っているように見えます。
http ヘッダの content-length は、文字通りコンテンツの長さです。ヘッダ等は含みません。

ついでに、もう少し関数を分けたほうが読み易いです。インデントが深すぎです。
get 処理と post 処理とか、ヘッダの処理とコンテンツの処理とか、レスポンスの処理とか…。

投稿2024/06/24 12:22

編集2024/06/24 12:23
jimbe

総合スコア13045

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.40%

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

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

質問する

関連した質問