TEST(UtilTest, Method) { bstr *method = bstr_dup_c("GET"); EXPECT_EQ(HTP_M_GET, htp_convert_method_to_number(method)); bstr_free(method); }
/** * Generic request line parser. * * @param connp * @return HTP_OK or HTP_ERROR */ int htp_parse_request_line_generic(htp_connp_t *connp) { htp_tx_t *tx = connp->in_tx; unsigned char *data = (unsigned char *)bstr_ptr(tx->request_line); size_t len = bstr_len(tx->request_line); size_t pos = 0; // The request method starts at the beginning of the // line and ends with the first whitespace character. while ((pos < len) && (!htp_is_space(data[pos]))) { pos++; } // No, we don't care if the method is empty. tx->request_method = bstr_memdup((char *)data, pos); if (tx->request_method == NULL) { return HTP_ERROR; } tx->request_method_number = htp_convert_method_to_number(tx->request_method); // Ignore whitespace after request method. The RFC allows // for only one SP, but then suggests any number of SP and HT // should be permitted. while ((pos < len) && (isspace(data[pos]))) { pos++; } size_t start = pos; // The URI ends with the first whitespace. while ((pos < len) && (!htp_is_space(data[pos]))) { pos++; } tx->request_uri = bstr_memdup((char *)data + start, pos - start); if (tx->request_uri == NULL) { return HTP_ERROR; } // Ignore whitespace after URI while ((pos < len) && (htp_is_space(data[pos]))) { pos++; } // Is there protocol information available? if (pos == len) { // No, this looks like a HTTP/0.9 request. tx->protocol_is_simple = 1; return HTP_OK; } // The protocol information spreads until the end of the line. tx->request_protocol = bstr_memdup((char *)data + pos, len - pos); if (tx->request_protocol == NULL) { return HTP_ERROR; } tx->request_protocol_number = htp_parse_protocol(tx->request_protocol); return HTP_OK; }
/** * Determines whether inbound parsing needs to continue or stop. In * case the data appears to be plain text HTTP, we try to continue. * * @param[in] connp * @return HTP_OK if the parser can resume parsing, HTP_DATA_BUFFER if * we need more data. */ htp_status_t htp_connp_REQ_CONNECT_PROBE_DATA(htp_connp_t *connp) { for (;;) {//;i < max_read; i++) { IN_PEEK_NEXT(connp); // Have we reached the end of the line? For some reason // we can't test after IN_COPY_BYTE_OR_RETURN */ if (connp->in_next_byte == LF || connp->in_next_byte == 0x00) break; IN_COPY_BYTE_OR_RETURN(connp); } unsigned char *data; size_t len; if (htp_connp_req_consolidate_data(connp, &data, &len) != HTP_OK) { fprintf(stderr, "htp_connp_req_consolidate_data fail"); return HTP_ERROR; } #ifdef HTP_DEBUG fprint_raw_data(stderr, "PROBING", data, len); #endif size_t pos = 0; size_t mstart = 0; // skip past leading whitespace. IIS allows this while ((pos < len) && htp_is_space(data[pos])) pos++; if (pos) mstart = pos; // The request method starts at the beginning of the // line and ends with the first whitespace character. while ((pos < len) && (!htp_is_space(data[pos]))) pos++; int methodi = HTP_M_UNKNOWN; bstr *method = bstr_dup_mem(data + mstart, pos - mstart); if (method) { methodi = htp_convert_method_to_number(method); bstr_free(method); } if (methodi != HTP_M_UNKNOWN) { #ifdef HTP_DEBUG fprint_raw_data(stderr, "htp_connp_REQ_CONNECT_PROBE_DATA: tunnel contains plain text HTTP", data, len); #endif connp->in_state = htp_connp_REQ_IDLE; } else { #ifdef HTP_DEBUG fprint_raw_data(stderr, "htp_connp_REQ_CONNECT_PROBE_DATA: tunnel is not HTTP", data, len); #endif connp->in_status = HTP_STREAM_TUNNEL; connp->out_status = HTP_STREAM_TUNNEL; } // not calling htp_connp_req_clear_buffer, we're not consuming the data return HTP_OK; }
htp_status_t htp_parse_request_line_generic_ex(htp_connp_t *connp, int nul_terminates) { htp_tx_t *tx = connp->in_tx; unsigned char *data = bstr_ptr(tx->request_line); size_t len = bstr_len(tx->request_line); size_t pos = 0; size_t mstart = 0; size_t start; size_t bad_delim; if (nul_terminates) { // The line ends with the first NUL byte. size_t newlen = 0; while ((pos < len) && (data[pos] != '\0')) { pos++; newlen++; } // Start again, with the new length. len = newlen; pos = 0; } // skip past leading whitespace. IIS allows this while ((pos < len) && htp_is_space(data[pos])) pos++; if (pos) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request line: leading whitespace"); mstart = pos; if (connp->cfg->requestline_leading_whitespace_unwanted != HTP_UNWANTED_IGNORE) { // reset mstart so that we copy the whitespace into the method mstart = 0; // set expected response code to this anomaly tx->response_status_expected_number = connp->cfg->requestline_leading_whitespace_unwanted; } } // The request method starts at the beginning of the // line and ends with the first whitespace character. while ((pos < len) && (!htp_is_space(data[pos]))) pos++; // No, we don't care if the method is empty. tx->request_method = bstr_dup_mem(data + mstart, pos - mstart); if (tx->request_method == NULL) return HTP_ERROR; #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, bstr_ptr(tx->request_method), bstr_len(tx->request_method)); #endif tx->request_method_number = htp_convert_method_to_number(tx->request_method); bad_delim = 0; // Ignore whitespace after request method. The RFC allows // for only one SP, but then suggests any number of SP and HT // should be permitted. Apache uses isspace(), which is even // more permitting, so that's what we use here. while ((pos < len) && (isspace(data[pos]))) { if (!bad_delim && data[pos] != 0x20) { bad_delim++; } pos++; } if (bad_delim) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request line: non-compliant delimiter between Method and URI"); } // Is there anything after the request method? if (pos == len) { // No, this looks like a HTTP/0.9 request. tx->is_protocol_0_9 = 1; tx->request_protocol_number = HTP_PROTOCOL_0_9; return HTP_OK; } start = pos; bad_delim = 0; // The URI ends with the first whitespace. while ((pos < len) && (data[pos] != 0x20)) { if (!bad_delim && htp_is_space(data[pos])) { bad_delim++; } pos++; } /* if we've seen some 'bad' delimiters, we retry with those */ if (bad_delim && pos == len) { // special case: even though RFC's allow only SP (0x20), many // implementations allow other delimiters, like tab or other // characters that isspace() accepts. pos = start; while ((pos < len) && (!htp_is_space(data[pos]))) pos++; } if (bad_delim) { // warn regardless if we've seen non-compliant chars htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request line: URI contains non-compliant delimiter"); } tx->request_uri = bstr_dup_mem(data + start, pos - start); if (tx->request_uri == NULL) return HTP_ERROR; #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); #endif // Ignore whitespace after URI. while ((pos < len) && (htp_is_space(data[pos]))) pos++; // Is there protocol information available? if (pos == len) { // No, this looks like a HTTP/0.9 request. tx->is_protocol_0_9 = 1; tx->request_protocol_number = HTP_PROTOCOL_0_9; return HTP_OK; } // The protocol information continues until the end of the line. tx->request_protocol = bstr_dup_mem(data + pos, len - pos); if (tx->request_protocol == NULL) return HTP_ERROR; tx->request_protocol_number = htp_parse_protocol(tx->request_protocol); #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, bstr_ptr(tx->request_protocol), bstr_len(tx->request_protocol)); #endif return HTP_OK; }
/** * Parse request line as Apache 2.2 does. * * @param connp * @return HTP_OK or HTP_ERROR */ int htp_parse_request_line_apache_2_2(htp_connp_t *connp) { htp_tx_t *tx = connp->in_tx; unsigned char *data = (unsigned char *) bstr_ptr(tx->request_line); size_t len = bstr_len(tx->request_line); size_t pos = 0; // In this implementation we assume the // line ends with the first NUL byte. if (tx->request_line_nul_offset != -1) { len = tx->request_line_nul_offset - 1; } // The request method starts at the beginning of the // line and ends with the first whitespace character. while ((pos < len) && (!htp_is_space(data[pos]))) { pos++; } // No, we don't care if the method is empty. tx->request_method = bstr_memdup((char *) data, pos); #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->request_method), bstr_len(tx->request_method)); #endif tx->request_method_number = htp_convert_method_to_number(tx->request_method); // Ignore whitespace after request method. The RFC allows // for only one SP, but then suggests any number of SP and HT // should be permitted. Apache uses isspace(), which is even // more permitting, so that's what we use here. while ((pos < len) && (isspace(data[pos]))) { pos++; } size_t start = pos; // The URI ends with the first whitespace. while ((pos < len) && (!htp_is_space(data[pos]))) { pos++; } tx->request_uri = bstr_memdup((char *) data + start, pos - start); if (tx->request_uri == NULL) { return HTP_ERROR; } #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); #endif // Ignore whitespace after URI while ((pos < len) && (htp_is_space(data[pos]))) { pos++; } // Is there protocol information available? if (pos == len) { // No, this looks like a HTTP/0.9 request. tx->protocol_is_simple = 1; return HTP_OK; } // The protocol information spreads until the end of the line. tx->request_protocol = bstr_memdup((char *) data + pos, len - pos); tx->request_protocol_number = htp_parse_protocol(tx->request_protocol); #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->request_protocol), bstr_len(tx->request_protocol)); #endif return HTP_OK; }