📄 http.l
字号:
/* * http.c -- module for dealing with HTTP/1.1 persistent connection * Created: Xie Han, OS lab of Peking University. <me@pku.edu> * * You can find all you need dealing with http message! * * Created: Oct 21 6:30am 2003. version 0.1.1 * # The data structure of http request and http response are drafted * out. Indeed there are serveral versions, and the final decision * is the most simple one. * # The BNFs are typed, which are taken from RFC 2616 & RFC 2396. * # An over-all designing scheme is coming to its own in my mind. * # "We are reading the first verse of the first chapter of a book * whose pages are infinite..." Yes, we are just beginning. * * Updated: Oct 22 4:54am 2003. version 0.1.2 * # I'v found the way out. We maintain a list each node of which is * a "struct __http_buffer_state". Each node has different sockfd. * It means we allocate every different sockfd a scanning buffer * in order not to mess up when users more than one sockfd. * # "int sockfd" field is added to "struct __http_request" & * "struct __http_response" so that users need not get a sockfd when * they are reading message body. * # The idea of what interfaces should be and how they work is * clearing up in my mind. And this module is expected to been very * complexed for me and very convinient for its users. * * Updated: Oct 23 4:50am 2003. version 0.1.2 * # Everyting is different. Now, HTTP_REQUEST & HTTP_RESPONSE are * derived from HTTP_MESSAGE. Parsing process is made simplier * by getting Request-Line and Status-Line at one time. * # A field of "state" is added to HTTP_MESSAGE in order to support * non-blocking IO (The message header need not to be transferred * at one time). * # A field of "request_method" is added to HTTP_RESPONSE in order * that we can caculate the transfer length of the response. * # I am stuck at calculating transfer length from message header. * It's not an easy task. */OCTET [\0-\377]CHAR [\0-\177]UPALPHA [A-Z]LOALPHA [a-z]DIGIT [0-9]CTL [\0-\37\177]CR \rLF \nSP \bHT \tCRLF {CR}{LF}LWS {CRLF}?({SP}|{HT})+TEXT [^\0-\37\177]HEX [A-Fa-f]|{DIGIT}token [^\0-\37\177-\377()<>@,;:\\"/[\]?={}\b\t]+separators [()<>@,;:\\"/[\]?={}]|{SP}|{HT}comment "("({ctext}|{quoted-pair}|{comment})*")"ctext [^\0-\37\177()]quoted-string \"({qdtext}|{quoted-pair})*\"qdtext [^\0-\37\177"]quoted-pair "\"{CHAR}HTTP-Version "HTTP/"{DIGIT}+"."{DIGIT}+method {token}Request-URI "*"|{absoluteURI}|{abs_path}|{authority}Status-Code {DIGIT}{3}Reason-Phrase [^\0-\37\177]*Request-Line {method}{SP}{Request-URI}{SP}{HTTP-Version}{CRLF}Status-Line {HTTP-Version}{SP}{Status-Code}{SP}{Reason-Phrase}{CRLF}message-header {filed-name}":"{field-value}?field-name {token}field-value ({field-content}|{LWS})*field-content {TEXT}*|{token}{separators}{quoted-string}URI-reference ({absoluteURI}|{relativeURI})?("#"{fragment})?absoluteURI {scheme}":"({hier_part}|{opaque_part})relativeURI ({net_path}|{abs_path}|{rel_path})("?"{query})?hier_part ({net_path}|{abs_path})("?"{query})?opaque_part {uric_no_slash}{uric}*uric_no_slash {unreserved}|{escaped}|";"|"?"|":"|"@"|"&"|"="|"+"|"$"|","net_path "//"{authority}{abs_path}?abs_path "/"{path_segments}rel_path {rel_segment}{abs_path}?rel_segment ({unreserved}|{escaped}|";"|"@"|"&"|"="|"+"|"$"|",")+scheme {alpha}({alpha}|{digit}|"+"|"-"|".")*authority {server}|{reg_name}reg_name ({unreserved}|{escaped}|"$"|","|";"|":"|"@"|"&"|"="|"+")+server (({userinfo}"@")?{hostport})?userinfo ({unreserved}|{escaped}|";"|":"|"&"|"="|"+"|"$"|",")*hostport {host}(":"{port})?host {hostname}|{IPv4address}hostname ({domainlabel}".")*{toplabel}"."?domainlabel {alphanum}|{alphanum}({alphanum}|"-")*{alphanum}toplabel {alpha}|{alpha}({alphanum}|"-")*{alphanum}IPv4address {digit}+"."{digit}+"."{digit}+"."{digit}+port {digit}*path ({abs_path}|{opaque_part})?path_segments {segment}("/"{segment})*segment {pchar}*(";"{param})*param {pchar}*pchar {unreserved}|{escaped}|":"|"@"|"&"|"="|"+"|"$"|","query {uric}*fragment {uric}*uric {reserved}|{unreserved}|{escaped}reserved ";"|"/"|"?"|":"|"@"|"&"|"="|"+"|"$"|","unreserved {alphanum}|{mark}mark "-"|"_"|"."|"!"|"~"|"*"|"'"|"("|")"escaped "%"{hex}{hex}hex digit|[A-Fa-f]alphanum {alpha}|{digit}alpha {lowalpha}|{upalpha}lowalpha [a-z]upalpha [A-Z]digit [0-9]%{#include <sys/types.h>#include <unistd.h>#include <list.h>#include "http.h"#define BUFFER_SIZE 1024struct __http_message{ int type; int sockfd; int state; struct list_head message_header; ssize_t transfer_length;};struct __http_request{ struct __http_message __base__; struct http_request_line request_line;};struct __http_response{ struct __http_message __base__; struct http_status_line status_line; char *request_method;};struct __http_buffer_state{ struct list_head list; int sockfd; char bytes[BUFFER_SIZE]; ssize_t size; char *curpos; ssize_t transfer_length;};static HTTP_MESSAGE __message;static LIST_HEAD(__buffer_list);static struct __http_buffer_state *__current_buffer;%}%%<REQUEST,RESPONSE>{CRLF} __current_buffer->curpos += yyleng;<REQUEST>.|\n { yyless(0); BEGIN REQUEST_LINE;}<RESPONSE>.|\n { yyless(0); BEGIN STATUS_LINE;}<REQUEST_LINE>{Request_Line}{CRLF} { char *pos; pos = strchr(yytext, ' '); if (((HTTP_REQUEST *)__message)->request_line.method = strdupn(yytext, pos - yytext)) { yytext = pos + 1; pos = strchr(yytext, ' '); if (((HTTP_REQUEST *)__message)->request_line.request_uri = strdupn(yytext, pos - yytext)) { yytext = pos + 1; pos = strchr(yytext, '\r'); if (((HTTP_REQUEST *)__message)->request_line.http_version = strdupn(yytext, pos - yytext)) { __current_buffer->curpos += yyleng; BEGIN (__message->state = MESSAGE_HEADER); YY_BREAK; } } }}<STATUS_LINE>{Status-Line}{CRLF} { char *pos; pos = strchr(yytext, ' '); if (((HTTP_RESPONSE *)__message)->status_line.http_version = strdupn(yytext, pos - yytext)) { yytext = pos + 1; pos = strchr(yytext, ' '); if (((HTTP_RESPONSE *)__message)->status_line.status_code = strdupn(yytext, pos - yytext)) { yytext = pos + 1; pos = strchr(yytext, '\r'); if (((HTTP_RESPONSE *)__message)->status_line.reason_phrase = strdupn(yytext, pos - yytext)) { __current_buffer->curpos += yyleng; BEGIN (__message->state = MESSAGE_HEADER); YY_BREAK; } } }}<MESSAGE_HEADER>{message-header}{CRLF} { struct __http_message_header *header; char *colon_pos; if (header = (struct __http_message_header *) malloc(sizeof (struct __http_message_header))) { colon_pos = strchr(yytext, ':'); if (header->field_name = strdupn(yytext, colon_pos - yytext)) { __current_buffer->curpos += yyleng; /* yyleng minus the field name, the colon, and the trailing * CRLF. If there is no blanks trailing the field value, * now yyleng is the length of field value. */ yyleng -= pos - yytext - 3; yytext = pos + 1; /* All the preceding or trailing blanks should be ignored. */ while (*yytext == ' ' || *yytext == '\t') yytext++; while (*(yytext + yyleng) == ' ' || *(yytext + yyleng) == '\t') yyleng--; if (header->field_value = strdupn(yytext, yyleng)) { list_add_tail(&header->list, &__message->message_header); YY_BREAK; } free(header->field_name); } free(header); }}<MESSAGE_HEADER>{CRLF} { __current_buffer->curpos += yyleng; __http_message_transfer_length(__message); return 0;}%%int yywrap(void){ YY_BUFFER_STATE buf; ssize_t nbytes; if ((nbytes = read(__current_buffer->sockfd, __current_buffer->bytes, BUFFER_SIZE)) > 0) { if (buf = yy_scan_bytes(__current_buffer->octets, __current_buffer->size)) { yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(buf); return 0; } } return 1;}ssize_t __from_header(struct list_head *list){}ssize_t __http_message_transfer_length(const HTTP_REQUEST *request){ return __from_header((HTTP_MESSAGE *)request->message_header));}ssize_t __http_response_transfer_length(const HTTP_RESPONSE *response){ char *code; if (strcmp(response->request_method, "HEAD") == 0) return 0; code = response->status_line.status_code; if (*code == '1' || strcmp(code, "204") == 0 || strcmp(code, "304") == 0) return 0; return __from_header((HTTP_MESSAGE *)response->message_header));}void __http_message_transfer_length(const HTTP_MESSAGE *message){ if (message->type == MT_REQUEST) message->transfer_length = __http_request_transfer_length((HTTP_REQUEST *)message); else message->transfer_length = __http_request_transfer_length((HTTP_RESPONSE *)message);}int __http_recv(int type, int sockfd){ YY_BUFFER_STATE yy_buffer; struct list_head *pos; struct __http_buffer_state *http_buffer; /* First we check whether "sockfd" is in our buffer list. */ list_for_each(pos, &__buffer_list) { if (sockfd == list_entry(pos, struct __http_buffer_state, list)->sockfd)) break; } if (pos == &__buffer_list) { /* "sockfd" is not in our buffer list. Create a new buffer for it. */ if (http_buffer = (struct __http_buffer_state *) malloc(sizeof (struct __http_buffer_state))) { INIT_LIST_HEAD(buffer->list); http_buffer->size = 0; http_buffer->curpos = http_buffer->octets; http_buffer->sockfd = sockfd; list_add_tail(&http_buffer->list, &__buffer_list); } else return -1; } else { http_buffer = list_entry(pos, struct __http_buffer_state, list); /* "sockfd" is in our buffer list and the previous transfer has * not completed. We should not transfer a new message. */ if (http_buffer->transfer_length != 0) return -1; } if (yy_buffer = yy_scan_bytes(http_buffer->curpos, http_buffer->size - (http_buffer->curpos - http_buffer->octets))) yy_switch_to_buffer(yy_buffer); else { if (pos == &__buffer_list) { list_del(&http_buffer->list); free(http_buffer); } return -1; } __current_buffer = http_buffer; BEGIN type; return yylex();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -