4

サーバーは HTTP ヘッダーとバイナリ ファイルを返します。このようなもの:

HTTP/1.1 200 OK
Date: Thu, 28 Jun 2012 22:11:14 GMT
Server: Apache/2.2.3 (Red Hat)
Set-Cookie: JSESSIONID=blabla; Path=/
Pragma: no-cache
Cache-Control: must-revalidate, no-store
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-disposition: inline; filename="foo.pdf"
Content-Length: 6231119
Connection: close
Content-Type: application/pdf

%PDF-1.6
%âãÏÓ
5989 0 obj
<</Linearized 1/L 6231119/O 5992/E 371504/N 1498/T 6111290/H [ 55176 6052]>>
endobj

xref
5989 2744
0000000016 00000 n
0000061228 00000 n
0000061378 00000 n

バイナリファイルだけをコピーしたい。しかし、ヘッダー部分がいつ終了したかを知るにはどうすればよいでしょうか? 行に a が含まれているかどうかをチェックしようとしまし\r\n\r\nたが、この標準はサーバーの応答には適用されず、クライアントにのみ適用されるようです。これは与えられました:

Content-disposition: inline; filename="foo.pdf"
Content-Length: 6231119
Connection: close
Content-Type: application/pdf

%PDF-1.6
%âãÏÓ
5989 0 obj
<</Linearized 1/L 6231119/O 5992/E 371504/N 1498/T 6111290/H [ 55176 6052]>>
endobj

xref
5989 2744
0000000016 00000 n

Cコードは次のとおりです。

while((readed = recv(sock, buffer, 128, 0)) > 0) {

    if(isnheader == 0 && strstr(buffer, "\r\n\r\n") != NULL)
        isnheader = 1;

        if(isnheader) 
          fwrite(buffer, 1, readed, fp);
}

アップデート:

continueif ステートメントにコントロールを入れます。

if(isnheader == 0 && strstr(buffer, "\r\n\r\n") != NULL) {
    isnheader = 1;
    continue;
}

まあ、それは期待どおりに動作します。しかし、@Alnitak が述べたように、安全ではありません。

4

2 に答える 2

17

\r\n\r\nヘッダーと本文は(RFC 2616のセクション4.1)で区切られているはずです。

ただし、一部のサーバーは、特にCGIが提供するヘッダーをサニタイズして、を確実に含めることができない場合に、\r送信行のみを省略して送信する場合があります。\n\r

また、読み取りをどのようにチャンク化するかを考慮する必要があります。セパレーターが128バイトのチャンクにまたがって、strstr呼び出しが機能しなくなる可能性があります。

于 2012-06-28T22:56:17.970 に答える
2

入力を正しく解析していません。これがあなたが間違ってしているいくつかのことです:

  • あなたのコードは、あなたのバッファがせいぜい1行のヘッダーデータを含むことを暗示しているようです。ただし、recv()はデータの「行」ではなく、バイナリデータのブロックで動作します。したがって、バッファの長さが128バイトであると指定すると、バッファが使用可能な場合は128バイトのデータでバッファを埋めようとします(128バイトのデータに複数の「行」が含まれている場合でも)。
  • コードでは、ヘッダーブレークの「\ r \ n」がrecv()への2つの異なる呼び出しによってバッファにプルされ、コードがヘッダーブレークを認識できなくなる可能性があることを考慮していません。
  • ヘッダーの区切りが見つかった場合(ヘッダーのサイズが適切な場合に発生する可能性があります)、最後のヘッダーを「\ r \ n」で終了し、ヘッダーの区切り( "\ r \ n")でプッシュすることになります。バイナリデータコピーに。

HTTPヘッダーの終わりを見つけて、サーバーの残りの応答をファイルストリームに書き込むクイック関数を作成しました。

void parse_http_headers(int s, FILE * fp)
{
   int       isnheader;
   ssize_t   readed;
   size_t    len;
   size_t    offset;
   size_t    pos;
   char      buffer[1024];
   char    * eol; // end of line
   char    * bol; // beginning of line

   isnheader = 0;
   len       = 0;

   // read next chunk from socket
   while((readed = read(s, &buffer[len], (1023-len))) > 0)
   {
      // write rest of data to FILE stream
      if (isnheader != 0)
         fwrite(buffer, 1, readed, fp);

      // process headers
      if (isnheader == 0)
      {
         // calculate combined length of unprocessed data and new data
         len += readed;

         // NULL terminate buffer for string functions
         buffer[len] = '\0';

         // checks if the header break happened to be the first line of the
         // buffer
         if (!(strncmp(buffer, "\r\n", 2)))
         {
            if (len > 2)
               fwrite(buffer, 1, (len-2), fp);
            continue;
         };
         if (!(strncmp(buffer, "\n", 1)))
         {
            if (len > 1)
               fwrite(buffer, 1, (len-1), fp);
            continue;
         };

         // process each line in buffer looking for header break
         bol = buffer;
         while((eol = index(bol, '\n')) != NULL)
         {
            // update bol based upon the value of eol
            bol = eol + 1; 

            // test if end of headers has been reached
            if ( (!(strncmp(bol, "\r\n", 2))) || (!(strncmp(bol, "\n", 1))) )
            {
               // note that end of headers has been reached
               isnheader = 1;

               // update the value of bol to reflect the beginning of the line
               // immediately after the headers
               if (bol[0] != '\n')
                  bol += 1;
               bol += 1;

               // calculate the amount of data remaining in the buffer
               len = len - (bol - buffer);

               // write remaining data to FILE stream
               if (len > 0)
                  fwrite(bol, 1, len, fp);

               // reset length of left over data to zero and continue processing
               // non-header information
               len = 0;
            };
         };

         if (isnheader == 0)
         { 
            // shift data remaining in buffer to beginning of buffer
            offset = (bol - buffer);
            for(pos = 0; pos < offset; pos++)
               buffer[pos] = buffer[offset + pos];

            // save amount of unprocessed data remaining in buffer
            len = offset;
         };
      };
   };

   return;
}

私はコードをテストしていないので、単純なエラーがあるかもしれませんが、Cのバッファーから文字列データを解析するための正しい方向を示しているはずです。

于 2012-06-29T05:05:40.117 に答える