diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index bd6c01ced..2d84a029c 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -664,12 +664,7 @@ srs_error_t SrsGoApiRequests::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess // request headers SrsJsonObject* headers = SrsJsonAny::object(); data->set("headers", headers); - - for (int i = 0; i < r->request_header_count(); i++) { - std::string key = r->request_header_key_at(i); - std::string value = r->request_header_value_at(i); - headers->set(key, SrsJsonAny::str(value.c_str())); - } + r->header()->dumps(headers); // server informations SrsJsonObject* server = SrsJsonAny::object(); diff --git a/trunk/src/protocol/srs_http_stack.cpp b/trunk/src/protocol/srs_http_stack.cpp index a95dc7ea2..b21db2d0b 100644 --- a/trunk/src/protocol/srs_http_stack.cpp +++ b/trunk/src/protocol/srs_http_stack.cpp @@ -173,6 +173,20 @@ void SrsHttpHeader::del(string key) } } +int SrsHttpHeader::count() +{ + return (int)headers.size(); +} + +void SrsHttpHeader::dumps(SrsJsonObject* o) +{ + map::iterator it; + for (it = headers.begin(); it != headers.end(); ++it) { + string v = it->second; + o->set(it->first, SrsJsonAny::str(v.c_str())); + } +} + int64_t SrsHttpHeader::content_length() { std::string cl = get("Content-Length"); @@ -776,13 +790,8 @@ srs_error_t SrsHttpCorsMux::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessag // If CORS enabled, and there is a "Origin" header, it's CORS. if (enabled) { - for (int i = 0; i < r->request_header_count(); i++) { - string k = r->request_header_key_at(i); - if (k == "Origin" || k == "origin") { - required = true; - break; - } - } + SrsHttpHeader* h = r->header(); + required = !h->get("Origin").empty(); } // When CORS required, set the CORS headers. diff --git a/trunk/src/protocol/srs_http_stack.hpp b/trunk/src/protocol/srs_http_stack.hpp index e27978df3..a6691ce33 100644 --- a/trunk/src/protocol/srs_http_stack.hpp +++ b/trunk/src/protocol/srs_http_stack.hpp @@ -45,6 +45,7 @@ class SrsHttpHeader; class ISrsHttpMessage; class SrsHttpMuxEntry; class ISrsHttpResponseWriter; +class SrsJsonObject; // From http specification // CR = @@ -129,6 +130,11 @@ public: // Delete the http header indicated by key. // Return the removed header field. virtual void del(std::string); + // Get the count of headers. + virtual int count(); +public: + // Dumps to a JSON object. + virtual void dumps(SrsJsonObject* o); public: // Get the content length. -1 if not set. virtual int64_t content_length(); @@ -505,9 +511,7 @@ public: // then query_get("start") is "100", and query_get("end") is "200" virtual std::string query_get(std::string key) = 0; // Get the headers. - virtual int request_header_count() = 0; - virtual std::string request_header_key_at(int index) = 0; - virtual std::string request_header_value_at(int index) = 0; + virtual SrsHttpHeader* header() = 0; public: // Whether the current request is JSONP, // which has a "callback=xxx" in QueryString. diff --git a/trunk/src/service/srs_service_http_conn.cpp b/trunk/src/service/srs_service_http_conn.cpp index 8525390b6..4048f2934 100644 --- a/trunk/src/service/srs_service_http_conn.cpp +++ b/trunk/src/service/srs_service_http_conn.cpp @@ -39,11 +39,13 @@ using namespace std; SrsHttpParser::SrsHttpParser() { buffer = new SrsFastStream(); + header = NULL; } SrsHttpParser::~SrsHttpParser() { srs_freep(buffer); + srs_freep(header); } srs_error_t SrsHttpParser::initialize(enum http_parser_type type, bool allow_jsonp) @@ -70,19 +72,22 @@ srs_error_t SrsHttpParser::initialize(enum http_parser_type type, bool allow_jso srs_error_t SrsHttpParser::parse_message(ISrsReader* reader, ISrsHttpMessage** ppmsg) { - *ppmsg = NULL; - srs_error_t err = srs_success; + + *ppmsg = NULL; - // reset request data. - field_name = ""; - field_value = ""; - expect_field_name = true; + // Reset request data. state = SrsHttpParseStateInit; - header = http_parser(); + hp_header = http_parser(); + // Reset the message url. url = ""; - headers.clear(); + // The body that we have read from cache. pbody = NULL; + // Reset the temporarily parsed header field. + expect_field_name = true; + // The header of the request. + srs_freep(header); + header = new SrsHttpHeader(); // do parse if ((err = parse_message_imp(reader)) != srs_success) { @@ -93,11 +98,9 @@ srs_error_t SrsHttpParser::parse_message(ISrsReader* reader, ISrsHttpMessage** p SrsHttpMessage* msg = new SrsHttpMessage(reader, buffer); // Initialize the basic information. - bool keep_alive = http_should_keep_alive(&header); - msg->set_basic(header.method, header.status_code, header.content_length, keep_alive); - - // initalize http msg, parse url. - if ((err = msg->update(url, jsonp, headers)) != srs_success) { + msg->set_basic(hp_header.method, hp_header.status_code, hp_header.content_length); + msg->set_header(header, http_should_keep_alive(&hp_header)); + if ((err = msg->set_url(url, jsonp)) != srs_success) { srs_freep(msg); return srs_error_wrap(err, "update message"); } @@ -142,11 +145,6 @@ srs_error_t SrsHttpParser::parse_message_imp(ISrsReader* reader) } } - // parse last header. - if (!field_name.empty() && !field_value.empty()) { - headers.push_back(std::make_pair(field_name, field_value)); - } - return err; } @@ -167,7 +165,7 @@ int SrsHttpParser::on_headers_complete(http_parser* parser) SrsHttpParser* obj = (SrsHttpParser*)parser->data; srs_assert(obj); - obj->header = *parser; + obj->hp_header = *parser; // save the parser when header parse completed. obj->state = SrsHttpParseStateHeaderComplete; @@ -196,7 +194,7 @@ int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length) srs_assert(obj); if (length > 0) { - obj->url.append(at, (int)length); + obj->url = string(at, (int)length); } srs_info("Method: %d, Url: %.*s", parser->method, (int)length, at); @@ -211,16 +209,12 @@ int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t l // field value=>name, reap the field. if (!obj->expect_field_name) { - obj->headers.push_back(std::make_pair(obj->field_name, obj->field_value)); - - // reset the field name when parsed. - obj->field_name = ""; - obj->field_value = ""; + obj->header->set(obj->field_name, obj->field_value); } obj->expect_field_name = true; if (length > 0) { - obj->field_name.append(at, (int)length); + obj->field_name = string(at, (int)length); } srs_info("Header field(%d bytes): %.*s", (int)length, (int)length, at); @@ -233,7 +227,7 @@ int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t l srs_assert(obj); if (length > 0) { - obj->field_value.append(at, (int)length); + obj->field_value = string(at, (int)length); } obj->expect_field_name = false; @@ -281,38 +275,42 @@ SrsHttpMessage::~SrsHttpMessage() srs_freepa(_http_ts_send_buffer); } -void SrsHttpMessage::set_basic(uint8_t method, uint16_t status, int64_t content_length, bool keep_alive) +void SrsHttpMessage::set_basic(uint8_t method, uint16_t status, int64_t content_length) { _method = method; _status = status; _content_length = content_length; +} + +void SrsHttpMessage::set_header(SrsHttpHeader* header, bool keep_alive) +{ + _header = *header; _keep_alive = keep_alive; + + // whether chunked. + chunked = (header->get("Transfer-Encoding") == "chunked"); } -srs_error_t SrsHttpMessage::update(string url, bool allow_jsonp, vector& headers) +srs_error_t SrsHttpMessage::set_url(string url, bool allow_jsonp) { srs_error_t err = srs_success; _url = url; - _headers = headers; - - // whether chunked. - std::string transfer_encoding = get_request_header("Transfer-Encoding"); - chunked = (transfer_encoding == "chunked"); - - // parse uri from url. - std::string host = get_request_header("Host"); - - // use server public ip when no host specified. + + // use server public ip when host not specified. // to make telnet happy. + std::string host = _header.get("Host"); if (host.empty()) { host= srs_get_public_internet_address(); } - - // parse uri to schema/server:port/path?query - std::string uri = "http://" + host + _url; + + // parse uri from schema/server:port/path?query + std::string uri = _url; + if (!host.empty()) { + uri = "http://" + host + _url; + } if ((err = _uri->initialize(uri)) != srs_success) { - return srs_error_wrap(err, "init uri"); + return srs_error_wrap(err, "init uri %s", uri.c_str()); } // parse ext. @@ -546,39 +544,9 @@ string SrsHttpMessage::query_get(string key) return v; } -int SrsHttpMessage::request_header_count() +SrsHttpHeader* SrsHttpMessage::header() { - return (int)_headers.size(); -} - -string SrsHttpMessage::request_header_key_at(int index) -{ - srs_assert(index < request_header_count()); - SrsHttpHeaderField item = _headers[index]; - return item.first; -} - -string SrsHttpMessage::request_header_value_at(int index) -{ - srs_assert(index < request_header_count()); - SrsHttpHeaderField item = _headers[index]; - return item.second; -} - -string SrsHttpMessage::get_request_header(string name) -{ - std::vector::iterator it; - - for (it = _headers.begin(); it != _headers.end(); ++it) { - SrsHttpHeaderField& elem = *it; - std::string key = elem.first; - std::string value = elem.second; - if (key == name) { - return value; - } - } - - return ""; + return &_header; } SrsRequest* SrsHttpMessage::to_request(string vhost) @@ -598,7 +566,7 @@ SrsRequest* SrsHttpMessage::to_request(string vhost) // generate others. req->tcUrl = "rtmp://" + vhost + "/" + req->app; - req->pageUrl = get_request_header("Referer"); + req->pageUrl = _header.get("Referer"); req->objectEncoding = 0; std::string query = _uri->get_query(); @@ -863,7 +831,7 @@ srs_error_t SrsHttpResponseWriter::send_header(char* data, int size) return srs_error_wrap(err, "filter header"); } - // write headers + // write header hdr->write(ss); // header_eof diff --git a/trunk/src/service/srs_service_http_conn.hpp b/trunk/src/service/srs_service_http_conn.hpp index da40ccea5..f4716b885 100644 --- a/trunk/src/service/srs_service_http_conn.hpp +++ b/trunk/src/service/srs_service_http_conn.hpp @@ -37,9 +37,6 @@ class ISrsReader; class SrsHttpResponseReader; class ISrsProtocolReadWriter; -// For http header. -typedef std::pair SrsHttpHeaderField; - // A wrapper for http-parser, // provides HTTP message originted service. class SrsHttpParser @@ -57,9 +54,9 @@ private: std::string field_name; std::string field_value; SrsHttpParseState state; - http_parser header; + http_parser hp_header; std::string url; - std::vector headers; + SrsHttpHeader* header; const char* pbody; public: SrsHttpParser(); @@ -88,9 +85,6 @@ private: static int on_body(http_parser* parser, const char* at, size_t length); }; -// for http header. -typedef std::pair SrsHttpHeaderField; - // A Request represents an HTTP request received by a server // or to be sent by a client. // @@ -100,34 +94,36 @@ typedef std::pair SrsHttpHeaderField; class SrsHttpMessage : public ISrsHttpMessage { private: - // The parsed url. - std::string _url; - // The extension of file, for example, .flv - std::string _ext; // The body object, reader object. // @remark, user can get body in string by get_body(). SrsHttpResponseReader* _body; - // Whether the body is chunked. - bool chunked; // Whether the body is infinite chunked. bool infinite_chunked; - // The uri parser - SrsHttpUri* _uri; // Use a buffer to read and send ts file. // TODO: FIXME: remove it. char* _http_ts_send_buffer; - // The http headers - std::vector _headers; - // The query map - std::map _query; // The transport connection, can be NULL. SrsConnection* owner_conn; private: uint8_t _method; uint16_t _status; int64_t _content_length; +private: + // The http headers + SrsHttpHeader _header; // Whether the request indicates should keep alive for the http connection. bool _keep_alive; + // Whether the body is chunked. + bool chunked; +private: + // The parsed url. + std::string _url; + // The extension of file, for example, .flv + std::string _ext; + // The uri parser + SrsHttpUri* _uri; + // The query map + std::map _query; private: // Whether request is jsonp. bool jsonp; @@ -138,9 +134,11 @@ public: virtual ~SrsHttpMessage(); public: // Set the basic information for HTTP request. - virtual void set_basic(uint8_t method, uint16_t status, int64_t content_length, bool keep_alive); + virtual void set_basic(uint8_t method, uint16_t status, int64_t content_length); + // Set HTTP header and whether the request require keep alive. + virtual void set_header(SrsHttpHeader* header, bool keep_alive); // set the original messages, then update the message. - virtual srs_error_t update(std::string url, bool allow_jsonp, std::vector& headers); + virtual srs_error_t set_url(std::string url, bool allow_jsonp); public: // Get the owner connection, maybe NULL. virtual SrsConnection* connection(); @@ -187,10 +185,7 @@ public: // then query_get("start") is "100", and query_get("end") is "200" virtual std::string query_get(std::string key); // Get the headers. - virtual int request_header_count(); - virtual std::string request_header_key_at(int index); - virtual std::string request_header_value_at(int index); - virtual std::string get_request_header(std::string name); + virtual SrsHttpHeader* header(); public: // Convert the http message to a request. // @remark user must free the return request. diff --git a/trunk/src/utest/srs_utest_http.cpp b/trunk/src/utest/srs_utest_http.cpp index fe1a3e865..f620a5671 100644 --- a/trunk/src/utest/srs_utest_http.cpp +++ b/trunk/src/utest/srs_utest_http.cpp @@ -134,6 +134,7 @@ VOID TEST(ProtocolHTTPTest, HTTPHeader) SrsHttpHeader h; h.set("Server", "SRS"); EXPECT_STREQ("SRS", h.get("Server").c_str()); + EXPECT_EQ(1, h.count()); stringstream ss; h.write(ss); @@ -141,17 +142,20 @@ VOID TEST(ProtocolHTTPTest, HTTPHeader) h.del("Server"); EXPECT_TRUE(h.get("Server").empty()); + EXPECT_EQ(0, h.count()); EXPECT_EQ(-1, h.content_length()); h.set_content_length(0); EXPECT_EQ(0, h.content_length()); + EXPECT_EQ(1, h.count()); h.set_content_length(1024); EXPECT_EQ(1024, h.content_length()); h.set_content_type("text/plain"); EXPECT_STREQ("text/plain", h.content_type().c_str()); + EXPECT_EQ(2, h.count()); } VOID TEST(ProtocolHTTPTest, HTTPCommonHandler)