如何格式化 HTTP 响应

sma*_*kid 3 sockets firefox network-programming google-chrome http

我用 C 编写了一个套接字程序。我使用这个程序作为使用 TCP 的聊天服务器/客户端。我试图通过将端口更改为 80 来更改聊天服务器以将其用作 HTTP 服务器。我参考了http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Example_session 中的 HTTP 请求/响应格式,并制作了我的程序以示例响应进行回复。我试过网址

http://127.0.0.1/ 
Run Code Online (Sandbox Code Playgroud)

在浏览器中。我的程序读取请求并回复响应。起初,我使用谷歌浏览器。Chrome 没有正确加载页面,直到我在 Content-Length 标头中添加了正确的数据长度。设置内容长度标题后,chrome 正确加载了页面。但是,firefox 不会加载页面。Firefox 没有显示任何错误,但仍在加载页面,就像仍在等待一些数据一样。只有当我停止服务器或关闭套接字时,才会加载完整的页面。我尝试按照 rfc2616 http://tools.ietf.org/html/rfc2616 进行操作,并准确做出响应,但结果仍然相同。

要求:

GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nUser-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:33.0) Gecko/20100101 Firefox/33.0\r\nAccept: text/ html,application/xhtml+xml,application/xml;q=0.9, / ;q=0.8\r\nAccept-Language: en-US,en;q=0.5\r\nAccept-Encoding: gzip, deflate\r\ n连接:保持活动\r\n\r\n

对于上述请求,我的程序使用以下响应和内容写入套接字。

回复:

HTTP/1.1 200 OK\r\n缓存控制:无缓存,私有\r\n内容长度:107\r\n日期:2014 年 11 月 24 日星期一 10:21:21 GMT\r\n\r\n

内容:

<html><head><title></title></head><body>TIME : 1416824843 <br>DATE: Mon Nov 24 15:57:23 2014 </body></html>
Run Code Online (Sandbox Code Playgroud)

此响应正在 Chrome 中加载,但未在 Firefox 中加载。Chrome 正在立即加载页面,而 Firefox 正在等待数据。请注意,数据长度 107 是在标题中指定的。我没有在 Firefox 中启用任何插件。我的 Firefox 版本在请求中。Chrome 版本:版本 38.0.2125.111(64 位)。

代码:

void *socket_read(void *args)
{
    int socket,*s,length;
    char buf[1024];
    s=(int *)args;
    socket=*s;
    while(1){
        buf[0]='\0';
        length=read(socket,buf,1024);
        if(length==0)
            break;
        else if(length==-1){
            perror("Read");
            return;
        }
        else{
            printf("Request: %s\n",buf);
            send_response(socket);
        }       
    }
    printf("End of read thread [%d]\n",socket);
}
int start_accept(int port)
{
    int socket,csocket;
    pthread_t thread;
    struct sockaddr_in client;
    socklen_t addrlen=sizeof(client);
    pthread_attr_t attr;
    socket=create_socket(port);
    while(1){
        if((csocket=accept(socket,(struct sockaddr *)&client,&addrlen))==-1)
        {   
            perror("Accept");
            break;
        }
        pthread_attr_init(&attr);
        if(0!=pthread_create(&thread,&attr,socket_read,&csocket))
        {
            perror("Read thread");
            return;
        }
        usleep(10000);
    }
}
void send_response(int socket)
{
    char buf1[1024];
    int content_length;
    char buf2[1024]="<html><head><title></title></head><body>TIME : 1416824843 <br>DATE: Mon Nov 24 15:57:23 2014 </body></html>";
    content_length=strlen(buf2);
    sprintf(buf1,"HTTP/1.1 200 OK\r\nCache-Control : no-cache, private\r\nContent-Length : %d\r\nDate : Mon, 24 Nov 2014 12:03:43 GMT\r\n\r\n",content_length);
    printf("Written: %d \n",write(socket,buf1,strlen(buf1)));
    fflush(stdout);
    printf("Written: %d \n",write(socket,buf2,content_length));
    fflush(stdout);
}
Run Code Online (Sandbox Code Playgroud)

sma*_*kid 7

我找到了问题所在。响应不正确。标题字段名称和冒号(':')之间不应有任何空格。在http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 中找到了这个。

我的正确答案是

HTTP/1.1 200 OK\r\nCache-Control: no-cache, private\r\nContent-Length: 107\r\nDate: Mon, 24 Nov 2014 10:21:21 GMT\r\n\r\n
Run Code Online (Sandbox Code Playgroud)

我在 'Content-Length' 和 ':' 之间加了一个空格。这就是 Firefox 忽略内容长度标头并读取套接字的原因。Chrome 接受带有空格的标题字段,因此该问题不会出现在 chrome 中。

删除空间后,程序工作正常。