29.Nginx HTTP之请求行解析函数ngx_http_parse_request_line

2023-05-16

Nginx的HTTP模块中使用ngx_http_parse_request_line函数来对读取的请求行进行解析,HTTP请求行的格式不是很复杂,但是要注意HTTP 0.9与1.0、1.1之间的区别;另外,作为Nginx的第一个版本,里面支持的请求方法也只有GET、POST和HEAD。


/* http/ngx_http_parse.c */

/* 解析HTTP请求行
 * param r: 待处理的HTTP请求
 *       b: 存放请求行内容的缓冲区
 * return : 成功解析完整的请求行时返回NGX_OK;
 *          成功解析了部分请求行时返回NGX_AGAIN;
 *          否则返回其他
 */
ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
{
    // HTTP 0.9    请求行格式: [请求方法][空格..空格][URL](空格..空格)(回车符)[换行符]
    // HTTP >= 1.0 请求行格式: [请求方法][空格..空格][URL][空格..空格][协议版本][回车符][换行符]
    
    u_char  ch, *p, *m;
    
    enum {
        sw_start = 0,             // 初始状态
        sw_method,                // 解析请求方法
        sw_space_after_method,    // 解析请求方法后紧跟的一个空格
        sw_spaces_before_uri,     // 解析URL前可能存在的多余空格
        sw_schema,                // 解析schema(http/https)
        sw_schema_slash,          // 解析<schema>:后紧跟的一个/
        sw_schema_slash_slash,    // 解析<schema>:/后紧跟的一个/
        sw_host,                  // 解析<schema>://后紧跟的主机(域名/IP)
        sw_port,                  // 解析<schema>://<host>:后紧跟的端口
        sw_after_slash_in_uri,    // 解析URL路径中/后的内容
        sw_check_uri,             // ?
        sw_uri,                   // ?
        sw_http_09,               // 解析URL后紧跟空格后的内容
        sw_http_H,                // 解析协议版本的第二个字符T
        sw_http_HT,               // 解析协议版本的第三个字符T
        sw_http_HTT,              // 解析协议版本的第四个字符P
        sw_http_HTTP,             // 解析协议版本的第五个字符/
        sw_first_major_digit,     // 解析协议版本的主版本号的第一个数字
        sw_major_digit,           // 解析协议版本的主版本号第一个数字后的数字或者.
        sw_first_minor_digit,     // 解析协议版本的次版本号的第一个数字
        sw_minor_digit,           // 解析协议版本的次版本号第一个数字后的数字
        sw_almost_done,           // 解析结束的\n
        sw_done                   // 解析完成
    } state;                      // 枚举变量: HTTP请求行解析状态

    // 获取请求r的当前状态state
    state = r->state;
    // 获取缓冲区b的有效内容起始地址p
    p = b->pos;

    while (p < b->last && state < sw_done) {
        // p小于b->last时, 表明缓冲区内的有效内容不为空;
        // state小于sw_done, 表明未解析完成
        
        // ch指向缓冲区有效内容的第一个字符, p后移一位
        ch = *p++;

        switch (state) {

        /* HTTP methods: GET, HEAD, POST */
        case sw_start:
            // 当前状态为sw_start即起始状态
            
            // 置r->request_start为p-1, 也就是当前字符的位置
            r->request_start = p - 1;

            if (ch == CR || ch == LF) {
                // 如果当前字符为\r或者\n
                
                // 跳过
                break;
            }

            if (ch < 'A' || ch > 'Z') {
                // 如果当前字符不是大写字母
                
                // 请求方法必须是由大写字母组成的, 所以返回NGX_HTTP_PARSE_INVALID_METHOD,
                // 从字面上可以看出, 这个返回值表示无效的请求方法
                return NGX_HTTP_PARSE_INVALID_METHOD;
            }

            // 置state为sw_method, 表示解析请求方法
            state = sw_method;
            break;

        case sw_method:
            // 当前状态为解析请求方法
            
            if (ch == ' ') {
                // 如果当前字符为空格
                
                // 说明遇到了请求方法后面的空格了, p-2即为请求方法的最后一个字符
                // 置r->method_end为p-1, 记录请求方法的结束位置
                r->method_end = p - 1;
                // r->request_start此时指向的是请求方法的第一个字符
                m = r->request_start;

                if (r->method_end - m == 3) {
                    // 如果请求方法子字符串的长度为3

                    if (m[0] == 'G' && m[1] == 'E' && m[2] == 'T') {
                        // 如果请求方法子字符串为GET
                        
                        // 置r->method为NGX_HTTP_GET
                        r->method = NGX_HTTP_GET;
                    }

                } else if (r->method_end - m == 4) {
                    // 如果请求方法子字符串的长度为4

                    if (m[0] == 'P' && m[1] == 'O'
                        && m[2] == 'T' && m[3] == 'T')
                    {
                        // 如果请求方法子字符串为POST
                        
                        // 置r->method为NGX_HTTP_POST
                        r->method = NGX_HTTP_POST;

                    } else if (m[0] == 'H' && m[1] == 'E'
                               && m[2] == 'A' && m[3] == 'D')
                    {
                        // 如果请求方法子字符串为HEAD
                        
                        // 置r->method为NGX_HTTP_HEAD
                        r->method = NGX_HTTP_HEAD;
                    }
                }

                // 解析完请求方法, 置state为sw_spaces_before_uri, 表示解析URL前面的空格
                // 因为此处已经解析到一个请求方法后的空格, 所以跳过状态sw_space_after_method,
                state = sw_spaces_before_uri;
                break;
            }

            if (ch < 'A' || ch > 'Z') {
                // 如果当前字符不是大写字母
                
                // 返回NGX_HTTP_PARSE_INVALID_METHOD
                return NGX_HTTP_PARSE_INVALID_METHOD;
            }

            break;

        case sw_space_after_method:
            // 当前状态为解析请求方法后紧跟的一个空格
            
            switch (ch) {
            case ' ':
                // 如果当前字符为空格
                
                // 置state为sw_spaces_before_uri, URL前面可能还有空格
                state = sw_spaces_before_uri;
                break;
            default:
                // 如果当前字符为非空格的字符
                
                // 请求方法和URL之间至少需要一个空格,
                // 返回NGX_HTTP_PARSE_INVALID_METHOD
                return NGX_HTTP_PARSE_INVALID_METHOD;
            }
            break;

        case sw_spaces_before_uri:
            // 当前状态为解析URL前可能存在的多余空格
            
            switch (ch) {
            case '/':
                // 如果当前字符为/, 说明遇到URL的第一个字符
                
                // 置r->uri_start为p-1, 记录URL的起始位置
                r->uri_start = p - 1;
                // 置state为sw_after_slash_in_uri, 表示解析URL路径中/后的内容
                state = sw_after_slash_in_uri;
                break;
            case ' ':
                // 如果当前字符为空格
                
                // 直接跳过
                break;
            default:
                if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
                    // 如果当前字符为大小写字母, 说明遇到schema(http/https)的第一个字符了
                    
                    // 置r->schema_start为p-1, 记录schema的起始位置
                    r->schema_start = p - 1;
                    // 置state为sw_schema, 表示解析schema
                    state = sw_schema;
                    break;
                }
                // 当前字符为其他字符, 表示请求有误, 返回NGX_HTTP_PARSE_INVALID_REQUEST,
                // 即无效请求
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_schema:
            // 当前状态为解析schema
            
            switch (ch) {
            case ':':
                // 如果当前字符为:, 说明遇到schema的后一个字符了
                
                // 置r->schema_end为p-1, 记录schema的结束位置
                r->schema_end = p - 1;
                // 置state为sw_schema_slash, 表示解析<schema>:后紧跟的一个/
                state = sw_schema_slash;
                break;
            default:
                if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
                    // 如果当前字符是大小写字符, 说明是我们想要的
                    
                    // 直接跳过
                    break;
                }
                // 当前字符为其他字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_schema_slash:
            // 当前状态为解析<schema>:后紧跟的一个/
            switch (ch) {
            case '/':
                // 如果当前字符正是/
                
                // 置state为sw_schema_slash_slash, 解析紧跟的一个/
                state = sw_schema_slash_slash;
                break;
            default:
                // 当前字符不为/, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_schema_slash_slash:
            // 当前状态为解析<schema>:/后紧跟的一个/
            
            switch (ch) {
            case '/':
                // 如果当前字符正是/
                
                // 置r->host_start为p-1, 记录URL中主机的起始位置
                r->host_start = p - 1;
                // 置state为sw_host, 表示解析<schema>://后紧跟的主机
                state = sw_host;
                break;
            default:
                // 当前字符不为/, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_host:
            // 当前状态为解析<schema>://后紧跟的主机
            
            switch (ch) {
            case ':':
                // 如果当前字符为:, 说明遇到主机后紧跟的一个:了
                
                // 置r->host_end为p-1, 记录主机的结束位置
                r->host_end = p - 1;
                // 置state为sw_port, 因为遇到主机后紧跟的:了, 那么此:后需要跟着端口号
                state = sw_port;
                break;
            case '/':
                // 如果当前字符是/, 因为主机后的:<port>不是必须的,
                // 说明遇到主机后紧跟的一个/了
                
                // 置r->host_end为p-1, 记录主机的结束位置
                r->host_end = p - 1;
                // 置r->uri_start为p-1, 记录URL中路径的起始地址
                r->uri_start = p - 1;
                // 置state为sw_after_slash_in_uri, 表示解析URL路径中/后的内容
                state = sw_after_slash_in_uri;
                break;
            default:
                if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')
                    || (ch >= '0' && ch <= '9') || ch == '.' || ch == '-')
                {
                    // 如果当前字符为大小写字母、数字、.、-, 说明是主机(域名/IP)的有效字符
                    
                    // 直接跳过
                    break;
                }
                // 当前字符为其他字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_port:
            // 当前状态为解析<schema>://<host>:后紧跟的端口
            switch (ch) {
            case '/':
                // 如果当前字符为/, 说明遇到端口后紧跟的一个/了
                
                // 置r->port_end为p-1, 记录端口的结束位置
                r->port_end = p - 1;
                // 置r->uri_start为p-1, 记录URL中路径的起始位置
                r->uri_start = p - 1;
                // 置state为sw_after_slash_in_uri, 表示解析URL路径中/后的内容
                state = sw_after_slash_in_uri;
                break;
            default:
                if (ch < '0' && ch > '9') {
                    // 如果当前字符不为数字, 端口必须由数字组成, 说明是非法字符
                    // 返回NGX_HTTP_PARSE_INVALID_REQUEST
                    return NGX_HTTP_PARSE_INVALID_REQUEST;
                }
                break;
            }
            break;

        case sw_after_slash_in_uri:
            // 当前状态为解析URL路径中/后的内容
            switch (ch) {
            case CR:
                // 如果当前字符为\r, 说明可能是HTTP 0.9
                
                // 置r->uri_end为p-1, 记录URL中路径的结束位置
                r->uri_end = p - 1;
                // 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_almost_done, 表示解析结束的\n
                state = sw_almost_done;
                break;
            case LF:
                // 如果当前字符为\n, 说明可能是HTTP 0.9
                
                // 置r->uri_end为p-1, 记录URL中路径的结束位置
                r->uri_end = p - 1;
                // 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            case ' ':
                // 如果当前字符为空格, 表示遇到URL(或者路径)后紧跟的一个空格
                
                // 置r->uri_end为p-1, 记录URL中路径的结束位置
                r->uri_end = p - 1;
                // 置state为sw_http_09, 表示解析URL后紧跟空格后的内容
                state = sw_http_09;
                break;
            case '.':
            case '%':
                // 如果当前字符为.或者%, 说明是复杂的URL
                
                // 置r->complex_uri为1
                r->complex_uri = 1;
                // 置state为sw_uri
                state = sw_uri;
                break;
            case '/':
                // 如果当前字符为/
                
                // 置r->complex_uri为1
                // 因为仍要解析/后的内容, 因此state不变
                r->complex_uri = 1;
                break;
            case '?':
                // 如果当前字符为?, 说明遇到了URL中的参数
                
                // 置r->args_start为p, 记录参数的起始位置
                r->args_start = p;
                // 置state为sw_uri
                state = sw_uri;
                break;
            default:
                // 如果当前字符为其他字符
                // 置state为sw_check_uri
                state = sw_check_uri;
                break;
            }
            break;

        case sw_check_uri:
            // 当前状态为sw_check_uri
            
            switch (ch) {
            case CR:
                // 如果当前字符为\r, 说明遇到了URL后紧跟的\r
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 显然是HTTP 0.9, 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_almost_done, 表示解析结束的\n
                state = sw_almost_done;
                break;
            case LF:
                // 如果当前字符为\n, 说明遇到了URL后紧跟的\n
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 显然是HTTP 0.9, 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            case ' ':
                // 如果当前字符为空格, 表明遇到URL后紧跟的一个空格
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 置state为sw_http_09, 表示解析URL后紧跟空格后的内容
                state = sw_http_09;
                break;
            case '.':
                // 如果当前字符为., 表明遇到扩展名
                
                // 置r->uri_ext为p, 记录扩展名的起始位置
                r->uri_ext = p;
                break;
            case '/':
                // 如果当前字符为/ 
                
                // 那么之前记录的"扩展名"其实不是真的扩展名, 置r->uri_ext为空
                r->uri_ext = NULL;
                // 置state为sw_after_slash_in_uri, 因为仍在解析URL且遇到了/
                state = sw_after_slash_in_uri;
                break;
            case '%':
                // 如果当前字符为%, 表明是复杂的URL
                
                // 置r->complex_uri为1
                r->complex_uri = 1;
                // 置state为sw_uri
                state = sw_uri;
                break;
            case '?':
                // 如果当前字符为?, 表明遇到了参数
                
                // 置r->args_start为p, 记录参数的起始位置
                r->args_start = p;
                // 置state为sw_uri
                state = sw_uri;
                break;
            }
            break;

        case sw_uri:
            // 当前状态为sw_uri
            
            switch (ch) {
            case CR:
                // 如果当前字符为\r, 说明遇到了URL后紧跟的\r
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 显然是HTTP 0.9, 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_almost_done, 表示解析结束的\n
                state = sw_almost_done;
                break;
            case LF:
                // 如果当前字符为\n, 说明遇到了URL后紧跟的\n
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 显然是HTTP 0.9, 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            case ' ':
                // 如果当前字符为空格, 表明遇到URL后紧跟的一个空格
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 置state为sw_http_09, 表示解析URL后紧跟空格后的内容
                state = sw_http_09;
                break;
            }
            break;

        case sw_http_09:
            // 当前状态为解析URL后紧跟空格后的内容
            
            switch (ch) {
            case ' ':
                // 如果当前字符为空格, 直接跳过
                break;
            case CR:
                // 如果当前字符为\r, 说明是HTTP 0.9
                
                // 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_almost_done, 表示解析结束的\n
                state = sw_almost_done;
                break;
            case LF:
                // 如果当前字符为\n, 说明是HTTP 0.9
                
                // 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            case 'H':
                // 如果当前字符是H, 说明是HTTP >= 1.0
                
                // 置state为sw_http_H, 表示解析协议版本的第二个字符T
                state = sw_http_H;
                break;
            default:
                // 当前字符为其他字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_http_H:
            // 当前状态为解析协议版本的第二个字符T
            switch (ch) {
            case 'T':
                // 如果当前字符正是T
                
                // 置state为sw_http_HT
                state = sw_http_HT;
                break;
            default:
                // 当前字符不为T, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_http_HT:
            // 当前状态为解析协议版本的第三个字符T
            
            switch (ch) {
            case 'T':
                // 如果当前字符正是T
                
                // 置state为sw_http_HTT
                state = sw_http_HTT;
                break;
            default:
                // 当前字符不为T, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_http_HTT:
            // 当前状态为解析协议版本的第四个字符P
            
            switch (ch) {
            case 'P':
                // 如果当前字符正是P
                
                // 置state为sw_http_HTTP
                state = sw_http_HTTP;
                break;
            default:
                // 当前字符不为P, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_http_HTTP:
            // 当前状态为解析协议版本的第五个字符/
            
            switch (ch) {
            case '/':
                // 如果当前字符正是/
                
                // 置state为sw_first_major_digit
                state = sw_first_major_digit;
                break;
            default:
                // 当前字符不为/, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_first_major_digit:
            // 当前状态为解析协议版本的主版本号的第一个数字
            if (ch < '1' || ch > '9') {
                // 如果当前字符不为数字1-9, 说明是无效字符;
                // 协议版本应该是在HTTP 1.0后才有的, 因此主版本号应该不小于1;
                // 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            // 置r->http_major为ch-'0', 记录主版本号
            r->http_major = ch - '0';
            // 置state为sw_major_digit, 表示解析协议版本的主版本号第一个数字后的数字或者.
            state = sw_major_digit;
            break;

        case sw_major_digit:
            // 当前状态为解析协议版本的主版本号第一个数字后的数字或者.
            
            if (ch == '.') {
                // 如果当前字符为., 说明遇到主版本号后紧跟的.了
                // 置state为sw_first_minor_digit, 表示解析次版本号的第一个数字
                state = sw_first_minor_digit;
                break;
            }

            if (ch < '0' || ch > '9') {
                // 如果当前字符不为数字, 说明是非法字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            // 更新主版本号r->http_major
            r->http_major = r->http_major * 10 + ch - '0';
            break;

        case sw_first_minor_digit:
            // 当前状态为解析协议版本的次版本号的第一个数字
            
            if (ch < '0' || ch > '9') {
                // 如果当前字符不为数字, 说明是非法字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            // 置r->http_minor为ch-'0', 记录次版本号
            r->http_minor = ch - '0';
            // 置state为sw_minor_digit, 表示解析协议版本的次版本号第一个数字后的数字
            state = sw_minor_digit;
            break;

        case sw_minor_digit:
            // 当前状态为解析协议版本的次版本号第一个数字后的数字
            
            if (ch == CR) {
                // 如果当前字符为\r, 说明遇到次版本号后紧跟的\r
                // 置state为sw_almost_done, 表示解析结束的\n
                state = sw_almost_done;
                break;
            }

            if (ch == LF) {
                // 如果当前字符为\n, 说明遇到次版本号后的\n
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            }

            if (ch < '0' || ch > '9') {
                // 如果当前字符不为数字, 说明是非法字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            // 更新次版本号r->http_minor
            r->http_minor = r->http_minor * 10 + ch - '0';
            break;

        case sw_almost_done:
            // 当前状态为解析结束的\n
            
            // 置r->request_end为p-2, 记录请求行有效内容的结束位置
            r->request_end = p - 2;
            switch (ch) {
            case LF:
                // 如果当前字符正是\n
                
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            default:
                // 如果当前字符不是\n, 那么就是非法字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_done:
            // 当前状态为解析完成, 直接退出循环
            break;
        }
    }

    // 置缓冲区的pos为p
    b->pos = p;

    if (state == sw_done) {
        // 如果state为sw_done, 表明解析完成
        
        if (r->request_end == NULL) {
            // 如果r->request_end为空
            
            // 置r->request_end为p-1, p-1即为请求行的结束位置
            r->request_end = p - 1;
        }

        // 求取HTTP版本, 规则为: 主版本号*1000+次版本号
        // 所以,0.9->9, 1.0->1000, 1.1->1001
        r->http_version = r->http_major * 1000 + r->http_minor;
        // 重置请求r的state为sw_start
        r->state = sw_start;

        if (r->http_version == 9 && r->method != NGX_HTTP_GET) {
            // 如果为HTTP 0.9且请求方法不为GET
            
            // 返回NGX_HTTP_PARSE_INVALID_09_METHOD, 说明HTTP 0.9只支持GET方法
            return NGX_HTTP_PARSE_INVALID_09_METHOD;
        }

        return NGX_OK;

    } else {
        // 没有解析完
        
        // 记录当前解析状态
        r->state = state;
        // 返回NGX_AGAIN
        return NGX_AGAIN;
    }
}





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

29.Nginx HTTP之请求行解析函数ngx_http_parse_request_line 的相关文章

  • 如何发送http basic auth post?

    我的任务是使用基本身份验证创建 http 帖子 我正在 asp net MVC 应用程序中使用 C 进行开发 我也得到过这个例子 POST v2 token endpoint HTTP 1 1 Authorization Basic Y2x
  • 我可以在服务器端应用程序(PHP、Ruby、Python 等)上读取 URL 的哈希部分吗?

    假设 URL 为 www example com val 1 part2 PHP可以读取请求变量val1使用 GET 数组 是哈希值part2还可读吗 或者这仅取决于浏览器和 JavaScript 主要问题是浏览器甚至不会发送带有片段部分的
  • 在 Android WebView 中获取 HTTP 状态代码

    我正在开发一个 Android 应用程序 该应用程序在 WebView 中加载网站 但有时该网站返回 HTTP 代码 500 我的问题是 有没有办法通过侦听器或另一个类从 WebView 获取 HTTP 状态代码 我尝试实现 WebView
  • Websocket-rails 不适用于 Nginx 和 Unicorn 的生产环境

    我有 Rails 3 2 应用程序和 gem websocket rails 0 7 在开发机器上 一切正常 在生产环境中 我使用 Nginx 1 6 作为代理服务器 使用 Unicorn 作为 http 服务器 Thin 用于独立模式 如
  • 使用凭证进行跨源资源共享

    我有一个跨多个子域 example com blog example com 和 app example com 的通用身份验证表单 登录表单必须将此数据提交到 example com 无论它显示在哪里 所以我想到使用 CORS 但是这样
  • 让请求在curl中工作,但在Python中不起作用

    我正在尝试使用curl 制作一个 put 方法 一切正常 并且我得到了JSON curl X PUT d foo more foo http ip 6001 whatever api key whatever 但是在使用python时由于某
  • X-FRAME-OPTIONS: DENY 通过 nginx 来自 Django 站点在哪里?

    我的 Django 网站使用django summernote https github com summernote django summernote在 iframe 中 并抛出此错误 多个具有冲突值的 X Frame Options
  • 如何在 nginx.conf 中引用操作系统环境变量

    在 nginx conf 中 设置变量后set name value 我可以像这样参考它 name 但是当我导出操作系统环境变量时 经过env name from env like https nginx org en docs ngx c
  • 使用 Clapprjs 在网页上流式传输 .m3u8

    我使用 nginx rtmp 将 rtmp 转换为 hls 并使用 Clappr 在网页中进行流式传输 但 Clappr 采用旧的 ts 段 导致 404 错误 因为它在服务器上被删除 如何解决这个问题 抱歉 这是我第一次使用 nginx
  • 使用 .htaccess 在 HTTP 和 HTTPS 之间正确切换

    我们有一个购物网站 托管在共享主机 Mediatemple Gridserver 上 网站的某些部分需要使用 HTTPS 结帐等 但其余部分应使用 HTTP 有谁知道我们如何始终强制对特定 URL 正确使用 HTTP HTTPS 我们已经让
  • Django:如何在ajax中返回模型表单集并在模板中使用

    我需要在运行时使用ajax动态地将表单添加到我的表单集中 我指的是使用 Ajax 将表单动态添加到 Django 表单集 https stackoverflow com questions 501719 dynamically adding
  • 多个资源的 REST 接口使用

    我目前正在通过 http 添加 REST API 到在线服务 我遇到了一个非常简单的问题 我找不到令我满意的答案 我主要有 2 个资源 用户 和 报告 正如您所猜测的那样 报告与用户相关联 与一个且仅一个 我的数据库中的外键 不管怎样 我有
  • Http PUT 请求到 jpeg

    我收到了如下 HTTP PUT PUT photo HTTP 1 1 X Apple AssetKey F92F9B91 954E 4D63 BB9A EEC771ADE6E8 X Apple Transition Dissolve Con
  • 如何设置http请求的源IP?

    在发送 http 请求之前 我需要设置源 IP 地址 用于 IP 欺骗等 用于建立http连接的类是HTTPURLConnection 我在 stackoverflow 上找到了下面的链接 这非常有用 注册和使用自定义 java net U
  • 为什么要使用 Node.js 安装服务器(Nginx、Apache...)? [复制]

    这个问题在这里已经有答案了 可能的重复 为什么 Node js Express Web 框架下需要 apache https stackoverflow com questions 9287747 why do we need apache
  • 如何修改 HttpUrlConnection 的标头

    我试图稍微改进一下 Java Html 文档 但我遇到了问题HttpUrlConntion 有一件事是 如果用户代理是 Java VM 某些服务器会阻止请求 另一个问题是HttpUrlConnection不设置Referrer or Loc
  • 为什么View Source会发出新的HTTP请求?

    我注意到 Firefox 和 Chrome 都发布了一个新的HTTP请求当你view the source对于您已经加载的网页 当页面本身加载缓慢或根本无法加载时 这尤其令人烦恼 这是为什么 他们不会已经缓存了最初接收的页面的现有源吗 是否
  • 在 Node.js / Express 中,如何“下载”页面并获取其 HTML?

    在代码中 我想下载 http www google com 并将其存储在字符串中 我知道如何在 python 的 urllib 中做到这一点 但是如何在 Node JS Express 中做到这一点呢 var util require ut
  • Nginx vs Apache 用于高流量站点

    Would nginx作为高流量网站的网络服务器是否是更合适的选择 我们将建立的网站是一个电子商务网站 如果这有什么不同的话 无论哪种方式 从技术角度来看 我真的对实际的 原因 感兴趣 即 为什么会nginx从技术角度来看 对于此类网站来说
  • Perl:读取网页文本文件并“打开”它

    我正在尝试创建一个脚本来读取文本文件 然后分析它们 无论文本文件是在线还是离线 离线部分完成 使用 open FILENAME anyfilename txt analyze file sub analyze file while

随机推荐

  • ROS | 话题通信的编程实现

    ROS 话题通信的编程实现 1 创建功能包2 节点编程与消息定义2 1 案例说明2 2 话题消息的定义2 3 创建 cpp文件2 4 话题发布者编程2 5 话题订阅者编程 3 配置与编译3 1 在CMaKeLists txt中添加编译选项3
  • Cocos2dx 3.0配置环境

    3 15 cocos2dx 3 0rc0 终于放出来了 在这里不得不吐槽一件事 xff0c 3 0版本从Alpha xff0c 到beta xff0c 再到rc xff0c 三个版本竟然都有各自创建项目的方式 xff0c 这样真的不会被人打
  • linux 开机运行应用程序

    把运行应用程序的脚本放在 etc rc local里面 xff0c 如果没有 etc rc local xff0c 需要执行前面的3条指令新建这个文件 注意执行应用最好要在后台执行 xff08 后面加个 amp xff09 xff0c 否则
  • arm linux游戏手柄(joystick)驱动移植

    在arm linux中移植usb joystick驱动 xff0c 参考了如下经验 xff1a Linux系统中使用Xbox360手柄 知 行 博客园 cnblogs com 使用BlueZ连接蓝牙手柄 Dokin丶的博客 CSDN博客 蓝
  • linux ubuntu下网络调试助手(GUI)工具

    mNetAssist这个工具在ubuntu下可以运行 xff0c 是个带界面的tcp调试工具 1 UDP通讯 xff1b 2 可做 TCP客户端 xff1b 3 可做 TCP服务器 xff1b 4 可以 十六进制 传送接收数据 5 可以传送
  • fft的通俗解释

    FFT是离散傅立叶变换的快速算法 xff0c 可以将一个信号变换 到频域 有些信号在时域上是很难看出什么特征的 xff0c 但是如 果变换到频域之后 xff0c 就很容易看出特征了 这就是很多信号 分析采用FFT变换的原因 另外 xff0c
  • linux 字符驱动完整框架(poll,async,waitqueue,nonblock等)

    一个linux内核驱动的完整框架 xff0c 包含了能遇到的大部分内容 xff0c 例如timer poll async waitqueue nonblock等等 xff0c 不过基本上没啥大用 xff0c 就是用来熟悉基础的 xff0c
  • vscode远程调试Linux CUDA程序

    参考了 xff1a CUDA 01 第一个程序 知乎 zhihu com 1 本地安装插件 xff1a remote ssh xff0c Microsoft C C 43 43 与NVIDIA Nsight Visual Studio Co
  • 移植MQTT-C库(附源码)

    Software mqtt org 中mqtt客户端的c库里面有一个叫MQTT C的库 xff0c 就2个实现文件 xff0c 算比较简单的了 xff0c 实现了基本的mqtt客户端功能 xff0c 移植一下试试 我的移植代码放在我的资源里
  • TCP协议的滑动窗口和流量控制算法(转)

    目录 滑动窗口 流量控制 操作系统缓冲区与滑动窗口的关系 窗口关闭 糊涂窗口综合症 拥塞控制 慢启动 拥塞避免算法 拥塞发生 快速恢复 拥塞算法示意图 引入 窗口概念的原因 我们都知道 TCP 是每发送一个数据 xff0c 都要进行一次确认
  • linux应用中的时间处理

    参考下 xff1a Linux下有关时间的函数 xff1a time times clock gettimeofday等 linux time函数 见牛羊的博客 CSDN博客 下面的代码基本涵盖了获取时间和操作计时的一些函数使用 xff1a
  • 从旋转向量到欧拉角的六种计算方法

    利用SolvePNP解出旋转向量 xff0c 旋转向量通过罗德里格斯公式解出旋转矩阵 xff0c 然后通过下面六种公式计算即可 xff0c 欧拉角有十二种 xff0c 六种是相对于自身参考系 xff0c 六种是相对于惯性参考系 xff0c
  • ROS | 服务通信的编程实现

    ROS 服务通信的编程实现 1 创建功能包2 节点编程与服务数据定义2 1 案例说明2 2 服务数据的定义2 3 创建 cpp文件2 4 客户端编程2 5 服务器编程 3 配置与编译3 1 在CMaKeLists txt中添加编译选项3 2
  • HTTP基础验证

    HTTP 内置基础验证 浏览器收到401状态码响应后 xff0c 弹出要求输入信息的对话框 通过验证则显示内容 xff0c 不通过不显示需要验证身份的内容 1 xff1b 手动HTTP基础验证 xff1a header 39 http 1
  • 位域,段域,联合体,结构体操作寄存器

    include lt stdio h gt typedef int Uint16 struct SCICCR BITS bit description Uint16 SCICHAR 3 2 0 Character length contro
  • C++ 网络编程之使用socket + epoll 模拟http 的请求与响应

    为了更好的理解http协议 xff0c 笔者使用了C 43 43 socket模拟了一个http服务器 xff0c 其中的服务器使用了epoll的方式 xff0c 并针对每一个新的连接开启新线程处理 大致分为三个部分 xff0c 具体代码可
  • 【Nova】nova-scheduler过滤称重

    在上一篇 nova scheduler调度过程分析 中 xff0c 对过滤称重的过程一笔带过了 xff0c 这篇着重介绍一下 首先 xff0c 我们声明一下host为主机 xff0c node为节点 xff0c 在OpenStack中一个h
  • 1.通过tcp从daytime服务器获取时间

    最近愈发觉得在学习源代码或者看书的时候 xff0c 做下读书笔记 xff0c 不仅能加深印象和理解 xff0c 同时也方便日后进行回顾 xff0c 所以就写下UNP UNIX网络编程 卷1的读书笔记 xff0c 涉及到的代码基本都是原作者提
  • 4.IPv4和IPv6地址长度

    IPv4地址的二进制形式长度为32 xff0c 使用我们常用的点分十进制形式进行表示那么最长长度为15 xff0c 例如 255 255 255 255 所以在posix的 lt netinet in h gt 中定义的IPv4地址字符串形
  • 29.Nginx HTTP之请求行解析函数ngx_http_parse_request_line

    Nginx的HTTP模块中使用ngx http parse request line函数来对读取的请求行进行解析 xff0c HTTP请求行的格式不是很复杂 xff0c 但是要注意HTTP 0 9与1 0 1 1之间的区别 xff1b 另外