c - GET 请求总是返回一个横幅,就像 HEAD 请求一样

标签 c sockets http get

您好,我正在编写一个简单的 C 程序,通过套接字向服务器发送请求

它通过send()函数向socket发送一个字符串,然后显示recv()获取的结果

如果我通过端口 80 上的 telnet 连接,我可以输入:

GET /index.html HTTP/1.0

然后插入两个换行符,我得到我的 html 页面。

如果我执行 HEAD 而不是 GET 它会显示横幅。

我无法在我的程序中重现这种行为,服务器总是响应一个HEAD请求,也就是说,我发送一个GET请求并得到横幅而不是 html 页面。我不明白这有什么问题。我确定请求在我输入时发送,因为我正在记录它..

更新了完整的程序代码

const char DEFAULT_REQUEST[] = "GET /index.html HTTP/1.0";

int main (int argc, char* argv[])
{
    char finalRequest[200];
    char* request = (char*)DEFAULT_REQUEST;

    if (argc < 3) 
    {
        if (argc < 2)
        {           
            printf("Usage: %s <hostname> <request>\n", argv[0]);
            exit(1);
        }

        log_warn("DEFAULT REQUEST \"%s\"", DEFAULT_REQUEST);
    } else request = argv[2];

    sprintf(finalRequest, "%s%s%s", request, EOL, EOL);

    log_info("HOST:  %s", argv[1]);

//RESOLVE HOST
    struct hostent *host_info = gethostbyname(argv[1]); 
    check(host_info != NULL, "Looking up hostname");

//CREATE SOCKET
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    check(socket_fd > -1, "Setting up socket");

//SETUP ADDRESS  
    struct sockaddr_in tareget_addr;
    tareget_addr.sin_family = AF_INET;
    tareget_addr.sin_addr = *((struct in_addr *) host_info->h_addr);
    tareget_addr.sin_port = htons(80);
    memset(&(tareget_addr.sin_zero), '\0', 8);

//CONNECT SOCKET
    int conn_res = connect(socket_fd, (struct sockaddr *) &tareget_addr, sizeof(struct sockaddr));
    check(conn_res > -1, "Connecting socket to target");

//SEND REQUEST          
    send_string(socket_fd, finalRequest);
    log_info("Request sent: %s\n", finalRequest);   

//PRINT RESULT

    const int recv_buff_size = 512;
    char recv_buffer[recv_buff_size];
    while (1)
    {
        int bytes_read = recv(socket_fd, recv_buffer, recv_buff_size, 0);
        if (bytes_read <= 0) break;
        printf("%s", recv_buffer);
    }

    close(socket_fd);
    return 0;
}

如您所见,我使用了两个 EOL,它等于 \r\n\r\n

它确实与 \r\n\r

一样工作

不适用于 \r\n

只有 \n\n\n

的段错误

最佳答案

由于我的评论似乎对您没有帮助,所以我拼凑了一个粗略的控制台程序来演示该过程。 (天啊——我忘了​​ C++ 字符串比 C 风格字符串有多少改进)

您没有提到操作系统(考虑到您查询的性质,您不会提到),所以我使用 win32 套接字和 win32 程序完成了它。

首先是输出:

Performing a HEAD request
-------
HTTP headers for 'http://www.example.com'
-------
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=604800
Content-Type: text/html
Date: Thu, 19 Feb 2015 11:57:18 GMT
ETag: "359670651"
Expires: Thu, 26 Feb 2015 11:57:18 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (cpm/F9D5)
X-Cache: HIT
x-ec-custom-error: 1
Content-Length: 1270
X-Cache: MISS from tx33vspep26a
Connection: close


Performing a GET request
-------
HTTP headers for 'http://www.example.com'
-------
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=604800
Content-Type: text/html
Date: Thu, 19 Feb 2015 11:57:19 GMT
ETag: "359670651"
Expires: Thu, 26 Feb 2015 11:57:19 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (cpm/F9D5)
X-Cache: HIT
x-ec-custom-error: 1
Content-Length: 1270
X-Cache: MISS from tx33vspep26a
Connection: close


HTTP content for 'http://www.example.com'
-------
<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
    body {
        background-color: #f0f0f2;
        margin: 0;
        padding: 0;
        font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;

    }
    div {
        width: 600px;
        margin: 5em auto;
        padding: 50px;
        background-color: #fff;
        border-radius: 1em;
    }
    a:link, a:visited {
        color: #38488f;
        text-decoration: none;
    }
    @media (max-width: 700px) {
        body {
            background-color: #fff;
        }
        div {
            width: auto;
            margin: 0 auto;
            border-radius: 0;
            padding: 1em;
        }
    }
    </style>
</head>

<body>
<div>
    <h1>Example Domain</h1>
    <p>This domain is established to be used for illustrative examples in documents. You may use this
    domain in examples without prior coordination or asking for permission.</p>
    <p><a href="http://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>

最后,生成它的代码(不要忘记链接到 ws2_32 库) 如果您在 mGetHeaders 中取消注释第 4 步之前的行,您可以看到请求字符串的格式与我之前在评论中提到的一样。

#include <windows.h>

#include <stdio.h>
#include <stdlib.h>

void mParseUrl(char *mUrl, char **serverName, char **filepath, char **filename)
{
    int n;
    char *tmpUrl;

    if (strcmpi(mUrl, "http://") != 0)
        tmpUrl = strdup( mUrl + 7);

    else if (strcmpi(mUrl, "https://") != 0)
        tmpUrl = strdup( mUrl + 8);

    char *slashPos, *lastSlashPos;
    slashPos = strchr(tmpUrl, '/');
    if (slashPos != NULL)
    {
        *serverName = (char*)calloc(slashPos - tmpUrl + 1, 1);
        strncpy(*serverName, tmpUrl, slashPos-tmpUrl);
        lastSlashPos = strrchr(filepath, '/');
        *filename = strdup(lastSlashPos+1);
    }

    else
    {
        *serverName = strdup(tmpUrl);
        *filepath = strdup("/");
        *filename = strdup("");
    }

    free(tmpUrl);
}

SOCKET connectToServer(char *szServerName, WORD portNum)
{
    struct hostent *hp;
    unsigned int addr;
    struct sockaddr_in server;
    SOCKET conn;

    conn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (conn == INVALID_SOCKET)
        return NULL;

    if(inet_addr(szServerName)==INADDR_NONE)
    {
        hp=gethostbyname(szServerName);
    }
    else
    {
        addr=inet_addr(szServerName);
        hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
    }

    if(hp==NULL)
    {
        closesocket(conn);
        return NULL;
    }

    server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
    server.sin_family=AF_INET;
    server.sin_port=htons(portNum);
    if(connect(conn,(struct sockaddr*)&server,sizeof(server)))
    {
        closesocket(conn);
        return NULL;
    }
    return conn;
}


char *mGetHeaders(char *szUrl)
{
//    string server, filepath, filename;
    char *serverName, *filepath, *filename;

    int portNum = 80;
    const int bufSize = 512;
    char sendBuffer[bufSize];
    char tmpBuffer[bufSize];
    char receiveBuffer[bufSize];
    char *result = NULL;
    SOCKET conn;
    long thisReadSize, totalBytesRead;

    // 1 - parse url into seperate components
    mParseUrl(szUrl, &serverName, &filepath, &filename);

    // 2 - aquire a connection
    conn = connectToServer( serverName, portNum);

    // 3 - send a request for the headers of the url
    sprintf(tmpBuffer, "HEAD %s HTTP/1.0\r\n", szUrl);
    strcpy(sendBuffer, tmpBuffer);
    sprintf(tmpBuffer, "HOST: %s\r\n", serverName );
    strcat(sendBuffer, tmpBuffer);

//    sprintf(tmpBuffer, "User-Agent: %s\r\n", "mUserAgent_0.0.1");
//    strcat(sendBuffer, tmpBuffer);

    sprintf(tmpBuffer, "\r\n");
    strcat(sendBuffer, tmpBuffer);
    send(conn, sendBuffer, strlen(sendBuffer), 0);

//    printf("Send Buffer: \n%s\n", sendBuffer);

    // 4 - get received bytes
    totalBytesRead = 0;
    while(1)
    {
        memset(receiveBuffer, 0, bufSize);
        thisReadSize = recv (conn, receiveBuffer, bufSize, 0);

        if ( thisReadSize <= 0 )
            break;

        result = (char*)realloc(result, thisReadSize+totalBytesRead);

        memcpy(result+totalBytesRead, receiveBuffer, thisReadSize);
        totalBytesRead += thisReadSize;
    }
    result = (char*)realloc(result, totalBytesRead+1);
    result[totalBytesRead] = NULL;

    closesocket(conn);

    free(serverName);
    free(filepath);
    free(filename);

    return result;
}

int getHeaderLength(char *content)
{
    const char *srchStr1 = "\r\n\r\n", *srchStr2 = "\n\r\n\r";
    char *findPos;
    int ofset = -1;

    findPos = strstr(content, srchStr1);
    if (findPos != NULL)
    {
        ofset = findPos - content;
        ofset += strlen(srchStr1);
    }

    else
    {
        findPos = strstr(content, srchStr2);
        if (findPos != NULL)
        {
            ofset = findPos - content;
            ofset += strlen(srchStr2);
        }
    }
    return ofset;
}

char *readUrl2(char *szUrl, long *bytesReturnedOut, char **headerOut)
{
    const int bufSize = 512;
    char readBuffer[bufSize], sendBuffer[bufSize], tmpBuffer[bufSize];
    char *tmpResult=NULL, *result;
    SOCKET conn;
//    string server, filepath, filename;
    char *serverName, *filepath, *filename;

    long totalBytesRead, thisReadSize, headerLen;

//    mParseUrl(szUrl, server, filepath, filename);
    mParseUrl(szUrl, &serverName, &filepath, &filename);

    ///////////// step 1, connect //////////////////////
    conn = connectToServer(serverName, 80);

    ///////////// step 2, send GET request /////////////
    sprintf(tmpBuffer, "GET %s HTTP/1.0", filepath);
    strcpy(sendBuffer, tmpBuffer);
    strcat(sendBuffer, "\r\n");
    sprintf(tmpBuffer, "Host: %s", serverName);
    strcat(sendBuffer, tmpBuffer);
    strcat(sendBuffer, "\r\n");
    strcat(sendBuffer, "\r\n");
    send(conn, sendBuffer, strlen(sendBuffer), 0);

    ///////////// step 3 - get received bytes ////////////////
    // Receive until the peer closes the connection
    totalBytesRead = 0;
    while(1)
    {
        memset(readBuffer, 0, bufSize);
        thisReadSize = recv (conn, readBuffer, bufSize, 0);

        if ( thisReadSize <= 0 )
            break;

        tmpResult = (char*)realloc(tmpResult, thisReadSize+totalBytesRead);

        memcpy(tmpResult+totalBytesRead, readBuffer, thisReadSize);
        totalBytesRead += thisReadSize;
    }

    headerLen = getHeaderLength(tmpResult);
    long contentLen = totalBytesRead-headerLen;
    result = (char*)calloc(contentLen+1, 1); //new char[contenLen+1];
    memcpy(result, tmpResult+headerLen, contentLen);
    result[contentLen] = 0x0;
    char *myTmp;

    myTmp = (char*)calloc(headerLen+1, 1); //new char[headerLen+1];
    strncpy(myTmp, tmpResult, headerLen);
    myTmp[headerLen] = NULL;
    free(tmpResult);
    *headerOut = myTmp;

    *bytesReturnedOut = contentLen;
    closesocket(conn);
    return(result);
}


int main()
{
    WSADATA wsaData;

    const char *soUrl = "http://www.example.com";

    if ( WSAStartup(0x101, &wsaData) != 0)
        return -1;

        printf("Performing a HEAD request\n");
        printf("-------\n");
        char *soHeaders = mGetHeaders(soUrl);
        printf("HTTP headers for '%s'\n", soUrl);
        printf("-------\n");
        printf("%s\n", soHeaders);
        free(soHeaders);

        long nBytesRetrived;
        char *responseHeader;

        printf("Performing a GET request\n");
        printf("-------\n");
        char *soContent = readUrl2(soUrl, &nBytesRetrived, &responseHeader);
        printf("HTTP headers for '%s'\n", soUrl);
        printf("-------\n");
        printf("%s\n", responseHeader);
        free(soHeaders);

        printf("HTTP content for '%s'\n", soUrl);
        printf("-------\n");
        printf("%s\n", soContent);
        free(soContent);


    WSACleanup();

    return 0;
}

关于c - GET 请求总是返回一个横幅,就像 HEAD 请求一样,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28597445/

相关文章:

有人可以给我一个 "pure pointer notation"到 C 数组的例子吗?

c - 循环求和给出意想不到的结果

c - 如何从 PROC 获取有关子进程的信息

javascript - Nodejs MySQL 循环中的多个查询

c# - 来自 UWP 的 MySQL 远程连接有套接字错误,但 TCP 连接

python - gevent 有基本的 http 处理程序吗?

C 内联汇编 - 'fst' 的操作数类型不匹配

java - BufferedImage 始终从 ByteArrayInputStream 传入 null

http - 如何使用 Coldfusion 获取最终重定向 URL

http - 重写重定向以包括用于访问服务的端口