static int request_check_hostname(server * srv, connection * con, buffer * host) { enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL; size_t i; int label_len = 0; size_t host_len; char *colon; int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */ int level = 0; UNUSED(srv); UNUSED(con); /* * hostport = host [ ":" port ] * host = hostname | IPv4address | IPv6address * hostname = *( domainlabel "." ) toplabel [ "." ] * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum * toplabel = alpha | alpha *( alphanum | "-" ) alphanum * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit * IPv6address = "[" ... "]" //IPv6地址用[]包围. * port = *digit */ /* * no Host: */ if (!host || host->used == 0) return 0; host_len = host->used - 1; /* * IPv6 adress */ if (host->ptr[0] == '[') { char *c = host->ptr + 1; int colon_cnt = 0; /* * check portnumber */ for (; *c && *c != ']'; c++) { if (*c == ':') { //至多7个分号。 if (++colon_cnt > 7) { return -1; } } else if (!light_isxdigit(*c)) { return -1; } } /* * missing ] */ if (!*c) { return -1; } /* * check port */ if (*(c + 1) == ':') { for (c += 2; *c; c++) { if (!light_isdigit(*c)) { return -1; } } } return 0; } if (NULL != (colon = memchr(host->ptr, ':', host_len))) { char *c = colon + 1; /* * check portnumber */ for (; *c; c++) { if (!light_isdigit(*c)) return -1; } /* * remove the port from the host-len */ host_len = colon - host->ptr; } /* * Host is empty */ if (host_len == 0) return -1; /* * if the hostname ends in a "." strip it */ if (host->ptr[host_len - 1] == '.') host_len -= 1; /* * scan from the right and skip the \0 */ for (i = host_len - 1; i + 1 > 0; i--) { const char c = host->ptr[i]; switch (stage) { case TOPLABEL: if (c == '.') { /*/** * header lines中的value,可以是以","分割的多个value。 * 这个函数将v中value,按照","分割成多个值,存放在vals中。 */ int http_request_split_value(array * vals, buffer * b) { char *s; size_t i; int state = 0; /* * parse * val1, val2, val3, val4 * into a array (more or less a explode() incl. striping of whitespaces */ if (b->used == 0) return 0; s = b->ptr; for (i = 0; i < b->used - 1;) { char *start = NULL, *end = NULL; data_string *ds; switch (state) { case 0: /* ws */ /* * skip ws */ for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++); state = 1; break; case 1: /* value */ start = s; for (; *s != ',' && i < b->used - 1; i++, s++); end = s - 1; //去掉空格 for (; (*end == ' ' || *end == '\t') && end > start; end--); if (NULL == (ds = (data_string *) array_get_unused_element(vals, TYPE_STRING))) { ds = data_string_init(); } buffer_copy_string_len(ds->value, start, end - start + 1); array_insert_unique(vals, (data_unset *) ds); if (*s == ',') { state = 0; i++; s++; } else { /* * end of string */ state = 2; } break; default: i++; break; } } return 0; } * only switch stage, if this is not the last character */ if (i != host_len - 1) { if (label_len == 0) { return -1; } /* * check the first character at right of the dot */ if (is_ip == 0) { if (!light_isalpha(host->ptr[i + 1])) { return -1; } } else if (!light_isdigit(host->ptr[i + 1])) { is_ip = 0; } else if ('-' == host->ptr[i + 1]) { return -1; } else { /* * just digits */ is_ip = 1; } stage = DOMAINLABEL; label_len = 0; level++; } else if (i == 0) { /* * just a dot and nothing else is evil */ return -1; } } else if (i == 0)
static handler_t proxy_http_parse_chunked_stream(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) { protocol_state_data *data = (protocol_state_data *)sess->proxy_con->protocol_data; char *err = NULL; off_t we_have = 0, we_want = 0; off_t chunk_len = 0; off_t offset = 0; buffer *b; chunk *c; char ch = '\0'; int finished = 0; UNUSED(srv); for (c = in->first; c && !finished;) { if(c->mem->used == 0) { c = c->next; continue; } switch(data->chunk_parse_state) { case HTTP_CHUNK_LEN: /* parse chunk len. */ for(offset = c->offset; (size_t)(offset) < (c->mem->used - 1) ; offset++) { ch = c->mem->ptr[offset]; if(!light_isxdigit(ch)) break; } if(offset > c->offset) { buffer_append_string_len(data->buf, (c->mem->ptr + c->offset), offset - c->offset); in->bytes_out += (offset - c->offset); c->offset = offset; } if (!(ch == ' ' || ch == '\r' || ch == ';')) { if (ch == '\0') { /* get next chunk from queue */ break; } /* protocol error. bad http-chunk len */ return HANDLER_ERROR; } data->chunk_len = strtol(BUF_STR(data->buf), &err, 16); data->chunk_offset = 0; buffer_reset(data->buf); data->chunk_parse_state = HTTP_CHUNK_EXTENSION; case HTTP_CHUNK_EXTENSION: /* find CRLF. discard chunk-extension */ for(ch = 0; (size_t)(c->offset) < (c->mem->used - 1) && ch != '\n' ;) { ch = c->mem->ptr[c->offset]; c->offset++; in->bytes_out++; } if(ch != '\n') { /* get next chunk from queue */ break; } if(data->chunk_len > 0) { data->chunk_parse_state = HTTP_CHUNK_DATA; } else { data->chunk_parse_state = HTTP_CHUNK_END; } case HTTP_CHUNK_DATA: chunk_len = data->chunk_len - data->chunk_offset; /* copy chunk_len bytes from in queue to out queue. */ we_have = c->mem->used - c->offset - 1; we_want = chunk_len > we_have ? we_have : chunk_len; if (c->offset == 0 && we_want == we_have) { /* we are copying the whole buffer, just steal it */ chunkqueue_steal_chunk(out, c); /* c is an empty chunk now */ } else { b = chunkqueue_get_append_buffer(out); buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want); c->offset += we_want; } chunk_len -= we_want; out->bytes_in += we_want; in->bytes_out += we_want; data->chunk_offset += we_want; if(chunk_len > 0) { /* get next chunk from queue */ break; } data->chunk_offset = 0; data->chunk_parse_state = HTTP_CHUNK_END; case HTTP_CHUNK_END: /* discard CRLF.*/ for(ch = 0; c->mem->used > 0 && (size_t)(c->offset) < (c->mem->used - 1) && ch != '\n' ;) { ch = c->mem->ptr[c->offset]; c->offset++; in->bytes_out++; } if(ch != '\n') { /* get next chunk from queue */ break; } /* final chunk */ if(data->chunk_len == 0) { finished = 1; } /* finished http-chunk. reset and parse next chunk. */ protocol_state_data_reset(data); break; } if((size_t)(c->offset) == c->mem->used - 1) { c = c->next; } } chunkqueue_remove_finished_chunks(in); if (finished) { sess->is_request_finished = 1; return HANDLER_FINISHED; } /* ran out of data. */ return HANDLER_GO_ON; }
static int request_check_hostname(buffer *host) { enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL; size_t i; int label_len = 0; size_t host_len, hostport_len; char *colon; int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */ int level = 0; /* * hostport = host [ ":" port ] * host = hostname | IPv4address | IPv6address * hostname = *( domainlabel "." ) toplabel [ "." ] * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum * toplabel = alpha | alpha *( alphanum | "-" ) alphanum * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit * IPv6address = "[" ... "]" * port = *digit */ /* IPv6 adress */ if (host->ptr[0] == '[') { char *c = host->ptr + 1; int colon_cnt = 0; /* check the address inside [...] */ for (; *c && *c != ']'; c++) { if (*c == ':') { if (++colon_cnt > 7) { return -1; } } else if (!light_isxdigit(*c) && '.' != *c) { return -1; } } /* missing ] */ if (!*c) { return -1; } /* check port */ if (*(c+1) == ':') { for (c += 2; *c; c++) { if (!light_isdigit(*c)) { return -1; } } } else if ('\0' != *(c+1)) { /* only a port is allowed to follow [...] */ return -1; } return 0; } hostport_len = host_len = buffer_string_length(host); if (NULL != (colon = memchr(host->ptr, ':', host_len))) { char *c = colon + 1; /* check portnumber */ for (; *c; c++) { if (!light_isdigit(*c)) return -1; } /* remove the port from the host-len */ host_len = colon - host->ptr; } /* Host is empty */ if (host_len == 0) return -1; /* if the hostname ends in a "." strip it */ if (host->ptr[host_len-1] == '.') { /* shift port info one left */ if (NULL != colon) memmove(colon-1, colon, hostport_len - host_len); buffer_string_set_length(host, --hostport_len); if (--host_len == 0) return -1; } /* scan from the right and skip the \0 */ for (i = host_len; i-- > 0; ) { const char c = host->ptr[i]; switch (stage) { case TOPLABEL: if (c == '.') { /* only switch stage, if this is not the last character */ if (i != host_len - 1) { if (label_len == 0) { return -1; } /* check the first character at right of the dot */ if (is_ip == 0) { if (!light_isalnum(host->ptr[i+1])) { return -1; } } else if (!light_isdigit(host->ptr[i+1])) { is_ip = 0; } else if ('-' == host->ptr[i+1]) { return -1; } else { /* just digits */ is_ip = 1; } stage = DOMAINLABEL; label_len = 0; level++; } else if (i == 0) { /* just a dot and nothing else is evil */ return -1; } } else if (i == 0) { /* the first character of the hostname */ if (!light_isalnum(c)) { return -1; } label_len++; } else { if (c != '-' && !light_isalnum(c)) { return -1; } if (is_ip == -1) { if (!light_isdigit(c)) is_ip = 0; } label_len++; } break; case DOMAINLABEL: if (is_ip == 1) { if (c == '.') { if (label_len == 0) { return -1; } label_len = 0; level++; } else if (!light_isdigit(c)) { return -1; } else { label_len++; } } else { if (c == '.') { if (label_len == 0) { return -1; } /* c is either - or alphanum here */ if ('-' == host->ptr[i+1]) { return -1; } label_len = 0; level++; } else if (i == 0) { if (!light_isalnum(c)) { return -1; } label_len++; } else { if (c != '-' && !light_isalnum(c)) { return -1; } label_len++; } } break; } } /* a IP has to consist of 4 parts */ if (is_ip == 1 && level != 3) { return -1; } if (label_len == 0) { return -1; } return 0; }