2-生成Http请求报文-BuildRequest

Please indicate the source: http://blog.csdn.net/gaoxiangnumber1

Welcome to my github: https://github.com/gaoxiangnumber1

  • webtest工作的第二步是生成http请求报文,对应函数BuildRequest(const char *url);
  • Http请求报文的格式请参见我的博客“HTTP权威指南”的“3-HTTP Messages”一文,您也可以直接阅读RFC2616。
  • BuildRequest(const char *url);主要有以下7个步骤:
    1. 检测URL的有效性。URL的语法为<scheme>://<host>:<port>/
      (1). scheme代表使用的协议(http/ftp等等):如果没有提供proxy server,那么只支持http协议。协议的名称不区分大小写,我们用函数IgnoreCaseMatch(url, "http://")进行匹配。
      (2). 查找子串“://”,若未找到退出程序。
      (3). 解析“:/”:必须要以‘/’结尾。
      (4). 判断URL长度是否合法。
    2. 如果URL有效,初始化host、request数组:分别用来存放host name、请求报文。
    3. 填充method字段。
      (1). 默认为GET方法。
      (2). 函数void StrCopy(char *dest, int *dest_index, const char *src):由于本程序只有在填充request时需要strcpy函数,所以特殊化。该函数每次填充字符时,从指定的索引开始,不复制src的结尾‘\0’字符。
    4. 填充request-url字段。
      (1). 当有proxy server时:不解析<host>:<port>部分,将整个url写入request数组。
      (2). 当没有proxy server时:解析。其中port可有可无,和‘:’保持一致。将‘/’之后的url写入request。
    5. 填充version字段:http 1.1.
    6. 填充header字段。
      (1). 当没有proxy时:写入Host header。
      (2). 当有proxy且force_reload = 1时:写入Pragma: no-cache\r\n
    7. 填充空行、结尾字符:”\r\n\0”。
  • 辅助的字符串处理函数。
// Copy string pointed to by src to string pointed to by dest start at dest_index.
// Not including the terminating null byte ('\0')
void StrCopy(char *dest, int *dest_index, const char *src)
{
    // Since we know our dest(request/host) must be large enough,
    // so we don't need check size.
    for(; *src; ++src) // Not including the terminating null byte ('\0')
    {
        *(dest + (*dest_index)++) = *src;
    }
}

// Return the index at which the substr begin in src, if match.
// -1 means not find.
int FindFirstSubstring(const char *src, const char *substr)
{
    int length = strlen(src);
    for(int index = 0; index < length; ++index)
    {
        if(*(src + index) == *substr) // Match the begin character, continue match.
        {
            for(const char *find = src + index; *substr && *find; ++substr, ++find)
            {
                if(*substr != *find) // Not match, return -1.
                {
                    return FAIL;
                }
            }
            return index; // Match success.
        }
    }
    return FAIL; // Not match.
}

// Return 0 if match, -1 otherwise.
int IgnoreCaseMatch(const char *large, const char *small)
{
    // For different case of the same character: lowercase > uppercase.
    // For the same case of different character: 'a' < 'z', 'A' < 'Z'.
    for(; *small; ++large, ++small)
    {
        // If *small is a letter, either lowercase or uppercase.
        if(('A' <= *small && *small <= 'Z') || ('a' <= *small && *small <= 'z'))
        {
            // The difference between the upper and lower case for the same character
            int differ = 'a' - 'A';
            if(!(*large == *small // Match exactly
                    || *large == *small - differ // Match uppercase for lowercase letter
                    || *large == *small + differ)) // Match lowercase for uppercase letter
            {
                return FAIL; // Not match.
            }
        }
        else if(*large != *small) // *small is not letter, so must match exactly.
        {
            return FAIL;
        }
    }
    return SUCCESS; // All match.
}

// Return the index of the first occurrence of ch in str: -1 if not find.
int FirstOccurIndex(const char *str, const char ch)
{
    for(int index = 0; *str; ++str, ++index)
    {
        if(*str == ch)
        {
            return index;
        }
    }
    return FAIL;
}
  • void BuildRequest(const char *url)完整源码:
void BuildRequest(const char *url) // Step 2. Build http request message.
{
    //printf("URL = %s\n", url);

    // Step 1. Check whether url is legal, URL syntax: `<scheme>://<host>:<port>/`
    if(proxy_host == NULL) // Check <scheme> supplied by user.
    {
        // Scheme names are case-insensitive.
        if(IgnoreCaseMatch(url, "http://") != 0)
        {
            fprintf(stderr, "\nOnly HTTP protocol is directly supported, set --proxy for others.\n");
            exit(BAD_PARAMETER);
        }
    }
    int first_colon = FindFirstSubstring(url, "://"); // The index of the first ':' appears in url.
    if(first_colon == FAIL) // If "://" can't be found in url.
    {
        fprintf(stderr, "\n%s: is not a valid URL.\n", url);
        exit(BAD_PARAMETER);
    }
    int url_host_begin = first_colon + 3; // Index where host name start: `://host:port/
    // Index where `host:port` end, i.e., the index of '/' in the whole url.
    int url_port_end = FirstOccurIndex(url + url_host_begin, '/') + url_host_begin;
    // Host name must end with '/'
    if(url_port_end == url_host_begin -1)
    {
        fprintf(stderr,"\nInvalid URL - host name must ends with '/'.\n");
        exit(BAD_PARAMETER);
    }
    if(strlen(url) > MAX_URL_SIZE) // If url is too long.
    {
        fprintf(stderr,"URL is too long.\n");
        exit(BAD_PARAMETER);
    }

    // Format of a request message:
    // <method> <request-URL> <version>"\r\n"
    // <headers>"\r\n"
    // "\r\n"
    // <entity-body>

    // Step 2. Initialize(zero) host and request array.
    bzero(host, MAX_HOST_NAME_SIZE);
    bzero(request, MAX_REQUEST_SIZE);

    // Step 3. Fill <method> field.
    switch(method)
    {
    default:
    case METHOD_GET:
        StrCopy(request, &request_index, "GET");
        break;
    case METHOD_HEAD:
        StrCopy(request, &request_index, "HEAD");
        break;
    case METHOD_OPTIONS:
        StrCopy(request, &request_index, "OPTIONS");
        break;
    case METHOD_TRACE:
        StrCopy(request, &request_index, "TRACE");
        break;
    }
    // Add the space between <method> and <request-URL>
    *(request + (request_index++)) = ' ';

    // Step 4. Fill <request-URL> field
    if(proxy_host == NULL) // No proxy, parse host-name and port-number.
    {
        int second_colon = FirstOccurIndex(url + url_host_begin, ':') + url_host_begin;
        int url_host_end = url_port_end; // If port number doesn't exist.
        // If port number exist.
        if(second_colon != url_host_begin -1 && second_colon < url_port_end)
        {
            // Get port number:
            int port = 0;
            for(int index = second_colon + 1; index < url_port_end; ++index)
            {
                port = port * 10 + *(url + index) - '0';
            }
            proxy_port = (port ? port : 80);
            //printf("proxy_port = %d\n", proxy_port);
            url_host_end = second_colon;
        }
        // Get host name.
        int dest_index = 0, src_index = url_host_begin;
        for(; src_index < url_host_end; ++dest_index, ++src_index)
        {
            host[dest_index] = *(url + src_index);
        }
        host[dest_index] = 0; // End host name.
        StrCopy(request, &request_index, url + url_port_end); // Fill <request-URL>
    }
    else
    {
        StrCopy(request, &request_index, url); // Fill <request-URL>
    }

    // Step 5. Fill <version> and this line's CRLF
    StrCopy(request, &request_index, " HTTP/1.1\r\n");

    // Step 6. Fill <headers>
    StrCopy(request, &request_index, "User-Agent: WebTest-Xiang Gao\r\n");
    if(proxy_host == NULL) // Without proxy server, fill <Host:> header.
    {
        StrCopy(request, &request_index, "Host: ");
        StrCopy(request, &request_index, host);
        StrCopy(request, &request_index, "\r\n");
    }
    if(force_reload && proxy_host != NULL)
    {
        StrCopy(request, &request_index, "Pragma: no-cache\r\n");
    }
    StrCopy(request, &request_index, "Connection: close\r\n");
    // Step 7. Add an empty line after all headers and add '\0' to end request array.
    StrCopy(request, &request_index, "\r\n\0");
    //printf("%s", request);
}

Please indicate the source: http://blog.csdn.net/gaoxiangnumber1

Welcome to my github: https://github.com/gaoxiangnumber1

你可能感兴趣的:(github,工作,函数,博客,url)