YETI_Result HttpHeaders::parse(BufferedInputStream & stream) { String header_name; String header_value; bool header_pending = false; String line; while (YETI_SUCCEEDED(stream.read_line(line, YETI_HTTP_PROTOCOL_MAX_LINE_LENGTH))) { if (line.get_length() == 0) { // end of headers break; } if (header_pending && (line[0] == ' ' || line[0] == '\t')) { header_value.append(line.get_chars() + 1, line.get_length() - 1); } else { if (header_pending) { header_value.trim(); add_header(header_name, header_value); header_pending = false; YETI_LOG_FINEST_2("header - %s: %s", header_name.get_chars(), header_value.get_chars()); } int colon_index = line.find(':'); if (colon_index < 1) { // invalid syntax, ignore continue; } header_name = line.left(colon_index); const char * value = line.get_chars() + colon_index + 1; while (*value == ' ' || *value == '\t') { value++; } header_value = value; header_pending = true; } } if (header_pending) { header_value.trim(); add_header(header_name, header_value); YETI_LOG_FINEST_2("header - %s: %s", header_name.get_chars(), header_value.get_chars()); } return YETI_SUCCESS; }
YETI_Result HttpResponse::parse(BufferedInputStream & stream, HttpResponse *& response) { response = NULL; String line; YETI_CHECK_FINE(stream.read_line(line, YETI_HTTP_PROTOCOL_MAX_LINE_LENGTH)); /*if (YETI_FAILED(res)) { if (res != YETI_ERROR_TIMEOUT && res != YETI_ERROR_EOS) YETI_CHECK_WARNING(res); return res; }*/ YETI_LOG_FINE_1("http response: %s", line.get_chars()); int first_space = line.find(' '); if (first_space < 1) return YETI_ERROR_HTTP_INVALID_RESPONSE_LINE; int second_space = line.find(' ', first_space + 1); if (second_space < 0) { if (line.get_length() != 12) { return YETI_ERROR_HTTP_INVALID_RESPONSE_LINE; } } else if (second_space != 4) { return YETI_ERROR_HTTP_INVALID_RESPONSE_LINE; } String protocol = line.sub_string(0, first_space); String status_code = line.sub_string(first_space + 1, 3); String reason_phrase = line.sub_string(first_space + 1 + 3 + 1, line.get_length() - (first_space + 1 + 3 + 1)); YETI_UInt32 status_code_int = 0; status_code.to_integer32(status_code_int); response = new HttpResponse(status_code_int, reason_phrase, protocol); YETI_Result result = response->parse_headers(stream); if (YETI_FAILED(result)) { delete response; response = NULL; } return result; }
YETI_Result File::save(const char * path, String & data) { DataBuffer buffer(data.get_chars(), data.get_length()); return File::save(path, buffer); }
YETI_Result HttpRequest::parse(BufferedInputStream & stream, const SocketAddress * endpoint, HttpRequest *& request) { // default return value request = NULL; skip_first_empty_line: // read the request line String line; YETI_CHECK_FINER(stream.read_line(line, YETI_HTTP_PROTOCOL_MAX_LINE_LENGTH)); YETI_LOG_FINEST_1("http request: %s", line.get_chars()); // when using keep-alive connections, clients such as XBox 360 // incorrectly send a few empty lines as body for GET requests // so we try to skip them until we find something to parse if (line.get_length() == 0) goto skip_first_empty_line; if (line.get_length() == 0) goto skip_first_empty_line; // check the request line int first_space = line.find(' '); if (first_space < 0) { YETI_LOG_FINE_1("http request: %s", line.get_chars()); return YETI_ERROR_HTTP_INVALID_REQUEST_LINE; } int second_space = line.find(' ', first_space + 1); if (second_space < 0) { YETI_LOG_FINE_1("http request: %s", line.get_chars()); return YETI_ERROR_HTTP_INVALID_REQUEST_LINE; } // parse the request line String method = line.sub_string(0, first_space); String uri = line.sub_string(first_space + 1, second_space - first_space - 1); String protocol = line.sub_string(second_space + 1); // create a request bool proxy_style_request = false; if (uri.starts_with("http://", true)) { // proxy-style request with absolute URI request = new HttpRequest(uri, method, protocol); proxy_style_request = true; } else { // normal absolute path request request = new HttpRequest("http:", method, protocol); } // parse headers YETI_Result result = request->parse_headers(stream); if (YETI_FAILED(result)) { delete request; request = NULL; return result; } // update the URL if (!proxy_style_request) { request->m_url_.set_scheme("http"); request->m_url_.parse_pathplus(uri); request->m_url_.set_port(YETI_HTTP_DEFAULT_PORT); // check for a Host: header HttpHeader * host_header = request->get_headers().get_header(YETI_HTTP_HEADER_HOST); if (host_header) { request->m_url_.set_host(host_header->get_value()); // host sometimes doesn't contain port if (endpoint) { request->m_url_.set_port(endpoint->get_port()); } } else { // use the endpoint as the host if (endpoint) { request->m_url_.set_host(endpoint->to_string()); } else { // use defaults request->m_url_.set_host("localhost"); } } } return YETI_SUCCESS; }
YETI_Result HttpEntity::set_input_stream(const String & string) { MemoryStream * memory_stream = new MemoryStream((const void *)string.get_chars(), string.get_length()); InputStreamReference body(memory_stream); return set_input_stream(body, true); }