0

C でソケットを使用して基本的な HTTP ファイル サーバーを作成しようとしていますが、主な問題が 2 つあります。

まず、ブラウザから「ip:port/」にアクセスしようとすると、index.html ファイルが表示されますが、まったく意味不明です。ただし、「ip:port/not_in_directory」にアクセスすると、小さなカスタム 404 メッセージが正常に返されます。デフォルトのファイルを既存のpdfファイルに設定すると、意味不明なものも戻ってきます(pdfの意味不明な長さ)。

次に、「ip:port/file_that_exists」にアクセスしようとすると、正しいファイルではなく 404 が返されます。デバッグ中に、scratch_pad には正しいファイル名があり、余分な文字や不足している文字がないことがわかりますが、!access(scratch_pad, R_OK) はまだ 0 になっています。ファイル名に?

EDIT:2番目の問題は解決されました(ファイル名として割り当て解除されたバッファへのポインタを使用していました)。ただし、ブラウザが取得するものはすべて意味不明です。重要でないコードをさらに削除しています。

#define FILE_NOT_FOUND "HTTP/1.0 404 FILE NOT FOUND\r\n"
#define FILE_FOUND "HTTP/1.0 200 OK\r\n"
#define SERVER_NAME "Server: Test Server\r\n"
#define CONTENT_TYPE "Content-Type: text/html\r\n"
#define DATE "Date: "
#define MESSAGE_BREAK "\r\n"
#define NOT_FOUND_HTML "<!DOCTYPE html>\n<html>\n<title>404 Not Found</title>\n<body>\n<p>Nope</p>\n</body>\n</html>\r\n"

  if(!access(pulled_name, R_OK | W_OK)) {
      printf("file found on server\n");
      server_file = fopen(pulled_name, "rb+");
      fseek(server_file, 0L, SEEK_END);
      file_size = ftell(server_file);
      fseek(server_file, 0l, SEEK_SET);
      printf("opened successfully and set file_size to %i\n", file_size);
      getting_time = time(NULL);
      c_time = localtime(&getting_time);
      current_time = asctime(c_time);
      printf("set time for message\n");

  message = malloc((int) strlen(FILE_FOUND)
                + (int) strlen(SERVER_NAME)
                + (int) strlen(CONTENT_TYPE)
                + (int) strlen(DATE)
                + (int) strlen(current_time)
                + (int) strlen(MESSAGE_BREAK));

  printf("malloc'ed message\n");

  message_size = (int)(strlen(message)*sizeof(char));     
  memset(message, 0, message_size);
  strcpy(message, FILE_FOUND);
  strcat(message, SERVER_NAME);
  strcat(message, CONTENT_TYPE);
  strcat(message, DATE);
  strcat(message, current_time);
  strcat(message, MESSAGE_BREAK);
  printf("built message\n");

  printf("set message_size to %i\n", message_size);
  while(total_sent < message_size) {
    n = send(new_socket_fd, message, message_size, 0);
    if (n==-1) {
      printf("error sending message\n");
      break;
    }
    total_sent += n;
    printf("sent %i\n", total_sent);
  }
  free(message);

  total_sent = 0;
  while(total_sent < file_size) {
    n = send(new_socket_fd, server_file, file_size, 0);
    if (n==-1) {
      printf("error sending file\n");
      break;
    }
    total_sent += n;
    printf("sent %i\n", total_sent);
  }
  fclose(server_file);
  close(new_socket_fd);
  printf("closed client connection!\n");
4

4 に答える 4

4

この間違いのいくつかの例があります:

memset(buffer, '\0', sizeof(buffer));

最初の引数のタイプが。の場合char*、これは、バッファーがヌル文字ではなく、最初のsizeof(char*)バイト(通常は4または8)のみで満たされることを意味します。この場合、それはbuffernullで終了しない可能性があることを意味します(recv()null文字を追加しないため)。との両方printf()strtok()、文字列引数をnullで終了する必要があります。printf("%s", p);null以外の終了文字列を使用して呼び出しを行う文字列の後に、ガベージ文字が出力されるのはよくあることです。

memset()最初の引数が指すバッファーのサイズを明示的に指定して、すべての呼び出しを修正します。

const size_t BUFFER_SIZE      = 512;
const size_t SCRATCH_PAD_SIZE = 256;
buffer                        = malloc(BUFFER_SIZE);     /*Check return value*/
scratch_pad                   = malloc(SCRATCH_PAD_SIZE);/*to ensure success.*/
memset(buffer,      0, BUFFER_SIZE);
memset(scratch_pad, 0, SCRATCH_PAD_SIZE);

は引数から省略できるようにsizeof(char)保証されています。1malloc()


その他の誤用memset()

memset(message, '0', sizeof(message)); 
  • '0'は文字ゼロであり、nullではありません
  • sizeof(message)それはsizeof(char*)

への変更:

memset(message, 0, /* the actual size of message*/ );
于 2012-09-28T13:21:46.787 に答える
1

コードには、見栄えがよくないものがいくつかあります。

ここ:

   buffer = malloc(sizeof(char)*512);
   scratch_pad = malloc(sizeof(char)*256);

strike_padは、割り当てられた領域へのポインタです。

しかし、その後、その領域へのポインターを失い、scratch_padをバッファーを指すように設定します。

   printf("request:\n%s\n", buffer);
   scratch_pad = strtok(buffer, "/");

次にここに:

   if (!strncmp(scratch_pad, "HTTP", 4)) {
       scratch_pad = "index.html";
       printf("request was for root directory\n");
   }

あなたはscratch_padを定数文字列に向けます。

あなたがしたとき

free(scratch_pad);

私はすべての地獄が緩むことを期待していました。

トークン化へのアプローチは少し危険です。私が見る最初の結果は、GETLOSTメソッドをの同義語として受け入れ、GETパスの処理に問題が発生することです(例GET /js/main.js HTTP/1.0)。

scratch_pad = strtok(buffer, "/");
printf("pulling request type\n");

if (!strncmp(scratch_pad, "GET", 3)) {
  printf("this is a Get\n");
  scratch_pad = strtok(NULL, " ");
  printf("pulling file name: >%s<\n", scratch_pad);
  if (!strncmp(scratch_pad, "HTTP", 4)) {
    scratch_pad = "index.html";
    printf("request was for root directory\n");
  }
  printf("requested file: %s\n", scratch_pad);
}

についてaccess()は、scratch_padに正しいファイルがあり、サーバーがWebルートで実行されている場合access()は、0を返す必要があります。そうでない場合は、の値を確認してerrnoください。

アップデート

私が上で書いたように、は(またはそうかもしれない)内部scratch_padのポインタです。だからあなたがするとき: buffer

free(buffer);
if(!access(scratch_pad, R_OK)) {

が指している領域がゴミ箱に捨てられることが起こるかもしれません(少なくとも数ミリ秒ではありませんが、ちょっと...) 。bufferそれからまた、scratch_padポイントは何でもあります。

そして、その時点でaccess(私が考えているので、これはゴミ箱を処理している可能性があります)、ゴミに取り組み、続行を拒否します。

確認するには、次のようにします。

if(access(scratch_pad、R_OK)){printf("ファイルにアクセスできません'%s' \ n"、scratch_pad); } そうしないと { ...

これを回避するには、別の方法でトークン化しbufferます。

例えば:

char * space; char * http;

//バッファはGET/this / path / to / file / name HTTP / 1.0 ... if(!strncmp(buffer、 "GET"、4))// GETではないif(NULL ==(space = strchr( buffer + 4、'')))//エラー:2番目のスペースがありません。if(!strncmp(space + 1、'HTTP /1。'、7))//エラー:GETはHTTP /1.somethingで終了しません//バッファ+4とスペースの間のすべてのバッファがファイル名になりますlen=スペースバッファ-4; strncpy(scratch_pad、buffer + 4、len); //文字列を終了しますscratch_pad[len]= 0x0;

//ここで、scratch_padには/で完全なファイル名が含まれていますが、//間違ったパスに対して相対的です。ドキュメントルートから開始する必要があります。//代わりに

#define DOCUMENT_ROOT "./" len = space-buffer-4; strcpy(scratch_pad、DOCUMENT_ROOT); strncpy(scratch_pad + strlen(DOCUMENT_ROOT)、buffer + 4、len); len + = strlen(DOCUMENT_ROOT); //文字列を終了します。これで、次のようになります。.//path/to/filescratch_pad [len] = 0x0; //実際にはここでrealpath()を実行する必要があります...

于 2012-09-28T13:31:00.313 に答える
0

ヘッダーが改行で終了していないように見えるDate: ...ため、MESSAGE_BREAKが飲み込まれます。また、すべての文字列の長さに+1を追加する理由がわかりません。

于 2012-09-28T13:22:28.330 に答える
0

私には奇妙に見えた2つのこと:

  1. ファイルの実際の内容に到達する前に、なぜ常に 404 メッセージを送信するのですか?
  2. 2 番目の send() が間違っています。なぜファイル記述子を送信しているのですか? あなたのバッファはどこですか?バッファ ポインタを提供し、ループごとに更新する必要があります。

ヒント: gcc -Wall はあなたの友達です。

于 2012-09-28T16:03:08.560 に答える