From 6ca9b774c154fcdcec6f77f001d0d191441125c1 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 1 Apr 2014 14:28:19 +0800 Subject: [PATCH] support http methods, support js crossdomain request --- trunk/src/app/srs_app_http.hpp | 3 +- trunk/src/app/srs_app_http_conn.cpp | 133 ++++++++++++++++++------- trunk/src/app/srs_app_http_conn.hpp | 28 +++++- trunk/src/kernel/srs_kernel_buffer.cpp | 22 +++- trunk/src/kernel/srs_kernel_buffer.hpp | 5 +- 5 files changed, 145 insertions(+), 46 deletions(-) diff --git a/trunk/src/app/srs_app_http.hpp b/trunk/src/app/srs_app_http.hpp index e58e166d2..b2def0155 100644 --- a/trunk/src/app/srs_app_http.hpp +++ b/trunk/src/app/srs_app_http.hpp @@ -46,7 +46,8 @@ namespace srs // HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all // protocol elements except the entity-body (see appendix 19.3 for // tolerant applications). - #define __CRLF __CR""__LF // 0x0D0A + #define __CRLF "\r\n" // 0x0D0A + #define __CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A }; #ifdef SRS_HTTP_CALLBACK diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index f22ec8055..8930cba6b 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -23,22 +23,52 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include +#include +using namespace std; + #include #include #include +#include +#include #define SRS_HTTP_HEADER_BUFFER 1024 +SrsHttpRequest::SrsHttpRequest() +{ + body = new SrsBuffer(); + state = SrsHttpParseStateInit; +} + +SrsHttpRequest::~SrsHttpRequest() +{ + srs_freep(body); +} + +void SrsHttpRequest::reset() +{ + state = SrsHttpParseStateInit; + body->clear(); + url = ""; +} + +bool SrsHttpRequest::is_complete() +{ + return state == SrsHttpParseStateComplete; +} + SrsHttpConn::SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd) : SrsConnection(srs_server, client_stfd) { + req = new SrsHttpRequest(); } -SrsHttpConn::~SrsHttpConn() +SrsHttpConn::~SrsHttpConn() { + srs_freep(req); } -int SrsHttpConn::do_cycle() +int SrsHttpConn::do_cycle() { int ret = ERROR_SUCCESS; @@ -69,7 +99,7 @@ int SrsHttpConn::do_cycle() SrsSocket skt(stfd); for (;;) { - if ((ret = process_request(&skt, &parser, &settings)) != ERROR_SUCCESS) { + if ((ret = parse_request(&skt, &parser, &settings)) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { srs_error("http client cycle failed. ret=%d", ret); } @@ -80,12 +110,12 @@ int SrsHttpConn::do_cycle() return ret; } -int SrsHttpConn::process_request(SrsSocket* skt, http_parser* parser, http_parser_settings* settings) +int SrsHttpConn::parse_request(SrsSocket* skt, http_parser* parser, http_parser_settings* settings) { int ret = ERROR_SUCCESS; // reset response header. - http_header = NULL; + req->reset(); // parser header. char buf[SRS_HTTP_HEADER_BUFFER]; @@ -102,13 +132,11 @@ int SrsHttpConn::process_request(SrsSocket* skt, http_parser* parser, http_parse srs_info("read_size=%d, nparsed=%d", (int)nread, (int)nparsed); // check header size. - if (http_header) { - int nb_body = nread - nparsed; + if (req->is_complete()) { + srs_trace("http request parsed, method=%d, url=%s, content-length=%"PRId64"", + req->header.method, req->url.c_str(), req->header.content_length); - srs_info("http header parsed, size=%d, content-length=%"PRId64", nb_body=%d", - http_header->nread, http_header->content_length, nb_body); - - return complete_header(skt, http_header, buf + nparsed, nb_body); + return process_request(skt); } if (nparsed != nread) { @@ -121,17 +149,38 @@ int SrsHttpConn::process_request(SrsSocket* skt, http_parser* parser, http_parse return ret; } -int SrsHttpConn::complete_header(SrsSocket* skt, http_parser* header, char* body, int nb_body) +int SrsHttpConn::process_request(SrsSocket* skt) { int ret = ERROR_SUCCESS; - char data[] = "HTTP/1.1 200 OK\r\n" - "Server: SRS/"RTMP_SIG_SRS_VERSION"\r\n" - "Content-Length: 15\r\n" - "Content-Type: text/html;charset=utf-8\r\n\r\n" - "hello http/1.1~"; + if (req->header.method == HTTP_OPTIONS) { + char data[] = "HTTP/1.1 200 OK" __CRLF + "Content-Length: 0"__CRLF + "Server: SRS/"RTMP_SIG_SRS_VERSION""__CRLF + "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT"__CRLF + "Access-Control-Allow-Origin: *"__CRLF + "Access-Control-Allow-Methods: GET, POST, HEAD, PUT, DELETE"__CRLF + "Access-Control-Allow-Headers: Cache-Control,X-Proxy-Authorization,X-Requested-With,Content-Type"__CRLF + "Content-Type: text/html;charset=utf-8"__CRLFCRLF + ""; + return skt->write(data, sizeof(data), NULL); + } else { + std::string tilte = "SRS/"RTMP_SIG_SRS_VERSION; + tilte += " hello http/1.1~\n"; - skt->write(data, sizeof(data), NULL); + std::stringstream ss; + ss << "HTTP/1.1 200 OK " << __CRLF + << "Content-Length: "<< tilte.length() + req->body->size() << __CRLF + << "Server: SRS/"RTMP_SIG_SRS_VERSION"" << __CRLF + << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF + << "Access-Control-Allow-Origin: *" << __CRLF + << "Access-Control-Allow-Methods: GET, POST, HEAD, PUT, DELETE" << __CRLF + << "Access-Control-Allow-Headers: Cache-Control,X-Proxy-Authorization,X-Requested-With,Content-Type" << __CRLF + << "Content-Type: text/html;charset=utf-8" << __CRLFCRLF + << tilte << (req->body->empty()? "":req->body->bytes()) + << ""; + return skt->write(ss.str().c_str(), ss.str().length(), NULL); + } return ret; } @@ -139,16 +188,19 @@ int SrsHttpConn::complete_header(SrsSocket* skt, http_parser* header, char* body int SrsHttpConn::on_message_begin(http_parser* parser) { SrsHttpConn* obj = (SrsHttpConn*)parser->data; - (void)obj; - srs_trace("***MESSAGE BEGIN***"); + obj->req->state = SrsHttpParseStateStart; + + srs_info("***MESSAGE BEGIN***"); + return 0; } int SrsHttpConn::on_headers_complete(http_parser* parser) { SrsHttpConn* obj = (SrsHttpConn*)parser->data; - (void)obj; - srs_trace("***HEADERS COMPLETE***"); + memcpy(&obj->req->header, parser, sizeof(http_parser)); + + srs_info("***HEADERS COMPLETE***"); // see http_parser.c:1570, return 1 to skip body. return 0; @@ -157,41 +209,48 @@ int SrsHttpConn::on_headers_complete(http_parser* parser) int SrsHttpConn::on_message_complete(http_parser* parser) { SrsHttpConn* obj = (SrsHttpConn*)parser->data; - srs_trace("***MESSAGE COMPLETE***\n"); - // save the parser when header parse completed. - obj->http_header = parser; + obj->req->state = SrsHttpParseStateComplete; + + srs_info("***MESSAGE COMPLETE***\n"); + return 0; } int SrsHttpConn::on_url(http_parser* parser, const char* at, size_t length) { SrsHttpConn* obj = (SrsHttpConn*)parser->data; - (void)obj; - srs_trace("Method: %d, Url: %.*s", parser->method, (int)length, at); + + if (length > 0) { + obj->req->url.append(at, (int)length); + } + + srs_info("Method: %d, Url: %.*s", parser->method, (int)length, at); + return 0; } -int SrsHttpConn::on_header_field(http_parser* parser, const char* at, size_t length) +int SrsHttpConn::on_header_field(http_parser* /*parser*/, const char* at, size_t length) { - SrsHttpConn* obj = (SrsHttpConn*)parser->data; - (void)obj; - srs_trace("Header field: %.*s", (int)length, at); + srs_info("Header field: %.*s", (int)length, at); return 0; } -int SrsHttpConn::on_header_value(http_parser* parser, const char* at, size_t length) +int SrsHttpConn::on_header_value(http_parser* /*parser*/, const char* at, size_t length) { - SrsHttpConn* obj = (SrsHttpConn*)parser->data; - (void)obj; - srs_trace("Header value: %.*s", (int)length, at); + srs_info("Header value: %.*s", (int)length, at); return 0; } int SrsHttpConn::on_body(http_parser* parser, const char* at, size_t length) { SrsHttpConn* obj = (SrsHttpConn*)parser->data; - (void)obj; - srs_trace("Body: %.*s", (int)length, at); + + if (length > 0) { + obj->req->body->append(at, (int)length); + } + + srs_info("Body: %.*s", (int)length, at); + return 0; } diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index e94edf48a..edd7e6ebf 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -36,19 +36,41 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include class SrsSocket; +class SrsBuffer; + +enum SrsHttpParseState { + SrsHttpParseStateInit = 0, + SrsHttpParseStateStart, + SrsHttpParseStateComplete +}; + +class SrsHttpRequest +{ +public: + std::string url; + http_parser header; + SrsBuffer* body; + SrsHttpParseState state; + + SrsHttpRequest(); + virtual ~SrsHttpRequest(); + + virtual void reset(); + virtual bool is_complete(); +}; class SrsHttpConn : public SrsConnection { private: - http_parser* http_header; + SrsHttpRequest* req; public: SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd); virtual ~SrsHttpConn(); protected: virtual int do_cycle(); private: - virtual int process_request(SrsSocket* skt, http_parser* parser, http_parser_settings* settings); - virtual int complete_header(SrsSocket* skt, http_parser* header, char* body, int nb_body); + virtual int parse_request(SrsSocket* skt, http_parser* parser, http_parser_settings* settings); + virtual int process_request(SrsSocket* skt); private: static int on_message_begin(http_parser* parser); static int on_headers_complete(http_parser* parser); diff --git a/trunk/src/kernel/srs_kernel_buffer.cpp b/trunk/src/kernel/srs_kernel_buffer.cpp index 2d70b365e..c29d02dfd 100644 --- a/trunk/src/kernel/srs_kernel_buffer.cpp +++ b/trunk/src/kernel/srs_kernel_buffer.cpp @@ -49,18 +49,34 @@ int SrsBuffer::size() return (int)data.size(); } +bool SrsBuffer::empty() +{ + return size() <= 0; +} + char* SrsBuffer::bytes() { return &data.at(0); } -void SrsBuffer::erase(int size) +void SrsBuffer::erase(int _size) { - data.erase(data.begin(), data.begin() + size); + if (_size == size()) { + clear(); + return; + } + + data.erase(data.begin(), data.begin() + _size); } -void SrsBuffer::append(char* bytes, int size) +void SrsBuffer::clear() { + data.clear(); +} + +void SrsBuffer::append(const char* bytes, int size) +{ + srs_assert(size > 0); data.insert(data.end(), bytes, bytes + size); } diff --git a/trunk/src/kernel/srs_kernel_buffer.hpp b/trunk/src/kernel/srs_kernel_buffer.hpp index d09e20c70..466dc1f8c 100644 --- a/trunk/src/kernel/srs_kernel_buffer.hpp +++ b/trunk/src/kernel/srs_kernel_buffer.hpp @@ -59,10 +59,11 @@ public: virtual ~SrsBuffer(); public: virtual int size(); + virtual bool empty(); virtual char* bytes(); virtual void erase(int size); -private: - virtual void append(char* bytes, int size); + virtual void clear(); + virtual void append(const char* bytes, int size); public: virtual int ensure_buffer_bytes(ISrsBufferReader* skt, int required_size); };