- 论坛徽章:
- 0
|
1、CON_STATE_REQUEST_END,从字面意思就可以看出来,这代表请求完成了,该做回应了。
- 1395 case CON_STATE_REQUEST_END: /* transient */
- 1396 if (srv->srvconf.log_state_handling) {
- 1397 log_error_write(srv, __FILE__, __LINE__, "sds",
- 1398 "state for fd", con->fd, connection_get_state(con->state));
- 1399 }
- 1400
- 1401 if (http_request_parse(srv, con)) {
- 1402 /* we have to read some data from the POST request */
- 1403
- 1404 connection_set_state(srv, con, CON_STATE_READ_POST);
- 1405
- 1406 break;
- 1407 }
- 1408
- 1409 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
- 1410
- 1411 break;
复制代码
这段代码比较简短,http_request_parse解析HTTP请求,然后将状态置为CON_STATE_HANDLE_REQUEST。http_request_parse函数位于request.c当中。这个函数比较长,有接近一千行的规模。-_-! 这个函数由两个循环构成。
第一循环的作用是获取HTTP协议版本号,HTTP请求类型,请求的URI,并且会检查HTTP版本是否合法,URI是否含有非法字符。处理的流程是,寻找第一行中的空格,如果找到第一个空格,那么空格前的字符串为请求类型,记下当前位置。寻找第一行中的第二个空格,如果找到,那么空格前从上一个位置起的字符串为URI,这代表要请求的资源。如果在第一行中找到第三个空格,这代表出错了。-_-!!!
- 496 case ' ':
- 497 switch(request_line_stage) {
- 498 case 0:
- 499 /* GET|POST|... */
- 500 method = con->parse_request->ptr + first;
- 501 first = i + 1;
- 502 break;
- 503 case 1:
- 504 /* /foobar/... */
- 505 uri = con->parse_request->ptr + first;
- 506 first = i + 1;
- 507 break;
- 508 default:
- 509 /* ERROR, one space to much */
- 510 con->http_status = 400;
- 511 con->response.keep_alive = 0;
- 512 con->keep_alive = 0;
- 513
- 514 if (srv->srvconf.log_request_header_on_error) {
- 515 log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
- 516 log_error_write(srv, __FILE__, __LINE__, "Sb",
- 517 "request-header:\n",
- 518 con->request.request);
- 519 }
- 520 return 0;
- 521 }
- 522
- 523 request_line_stage++; // 注意这一行
- 524 break;
复制代码
下一步是找到表示行结束的\r\n。
- switch(*cur) {
- 324 case '\r':
- 325 if (con->parse_request->ptr[i+1] == '\n') {
- 330 /* \r\n -> \0\0 */
- 331 con->parse_request->ptr[i] = '\0';
- 332 con->parse_request->ptr[i+1] = '\0';
- ....
- 349
- 350 proto = con->parse_request->ptr + first;
- 351
- 352 *(uri - 1) = '\0'; // 确定URI
- 353 *(proto - 1) = '\0'; // 确定协议
- ...
- 371 con->request.http_method = r; // 确定请求类型,为GET
- ...
- 487 buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
- 488
- 489 con->http_status = 0;
- 490
- 491 i++;
- 492 line++; // 注意这一行,如果执行到这里,下轮for循环就退出
- 493 first = i+1;
- 494 }
- 495 break;
复制代码
第二个循环的作用是取HTTP头,同时还检查是否有非法字符。处理的流程是,先寻找:号,这个是分隔符,用来分隔头名称和值。代码中分别使用key和value来表示,另外使用is_key这个变量来表示是否已经找到了key。代码分为if(is_key) ... else 两块。is_key的初始值为1,所以代码一开始进入的是if(is_key)的部分,一直到下面的代码。
- 558 case ':':
- 559 is_key = 0;
- 560
- 561 value = cur + 1;
- 562
- 563 if (is_ws_after_key == 0) {
- 564 key_len = i - first;
- 565 }
- 566 is_ws_after_key = 0;
- 567
- 568 break;
复制代码
如果找到了:号,下一次循环进入的就是else部分了。这里说的只是正常情况,如果出错了或者有异常的话,就退出了。再看看else部分里的代码。
- 760 int s_len;
- 761 key = con->parse_request->ptr + first; // 取得key
- 762
- 763 s_len = cur - value;
- 764
- 765 /* strip trailing white-spaces */
- 766 for (; s_len > 0 &&
- 767 (value[s_len - 1] == ' ' ||
- 768 value[s_len - 1] == '\t'); s_len--);
- 769
- 770 value[s_len] = '\0'; // 取得value
- 771
复制代码
如果一行结束了,就把key和value存起来。
- 772 if (s_len > 0) {
- 773 int cmp = 0;
- 774 if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
- 775 ds = data_string_init();
- 776 }
- 777 buffer_copy_string_len(ds->key, key, key_len);
- 778 buffer_copy_string_len(ds->value, value, s_len);
- 把取到的HTTP头加入队列中。然后再对几个头做一些处理,"Connection", "Content-Length","Content-Type","Expect","Host","If-Modified-Since"等等……最后做一下初始化,进入下一轮循环。
- [code]
- 996 i++;
- 997 first = i+1;
- 998 is_key = 1; // 注意这一行,恢复原始值
- 999 value = 0;
复制代码
循环结束以后,所有的HTTP头都读出来了。最后还要做一些后期工作,这里不详细讲了。到这里为止,这个复杂的函数就讲完了。接着上面的讲,现在设置状态为CON_STATE_HANDLE_REQUEST,要开始处理请求了。
[ 本帖最后由 李营长 于 2010-1-6 17:45 编辑 ] |
|