diff --git a/trunk/configure b/trunk/configure index 7101e99ae..66bba5a19 100755 --- a/trunk/configure +++ b/trunk/configure @@ -204,8 +204,9 @@ help: @echo " uninstall uninstall srs from prefix path" clean: - (cd ${SRS_OBJS}; rm -f rm -rf srs bandwidth srs_utest) - (cd ${SRS_OBJS}; rm -rf src research include lib utest) + (cd ${SRS_OBJS}; rm -rf srs bandwidth srs_utest) + (cd ${SRS_OBJS}; rm -rf src research include lib) + (cd ${SRS_OBJS}/utest; rm -rf *.o *.a) (cd research/librtmp; make clean) (cd research/api-server/static-dir; rm -rf crossdomain.xml forward live players) diff --git a/trunk/src/app/srs_app_http.cpp b/trunk/src/app/srs_app_http.cpp index bb1358cee..40244b0fe 100644 --- a/trunk/src/app/srs_app_http.cpp +++ b/trunk/src/app/srs_app_http.cpp @@ -43,6 +43,9 @@ using namespace srs; #define SRS_DEFAULT_HTTP_PORT 80 #define SRS_HTTP_RESPONSE_OK "0" +#define SRS_HTTP_HEADER_BUFFER 1024 +#define SRS_HTTP_BODY_BUFFER 32 * 1024 + SrsHttpUri::SrsHttpUri() { port = SRS_DEFAULT_HTTP_PORT; @@ -153,13 +156,13 @@ int SrsHttpClient::post(SrsHttpUri* uri, std::string req, std::string& res) // POST %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s std::stringstream ss; ss << "POST " << uri->get_path() << " " - << "HTTP/1.1" << CRLF - << "Host: " << uri->get_host() << CRLF - << "Connection: Keep-Alive" << CRLF - << "Content-Length: " << std::dec << req.length() << CRLF - << "User-Agent: " << RTMP_SIG_SRS_NAME << RTMP_SIG_SRS_VERSION << CRLF - << "Content-Type: text/html" << CRLF - << CRLF + << "HTTP/1.1" << __CRLF + << "Host: " << uri->get_host() << __CRLF + << "Connection: Keep-Alive" << __CRLF + << "Content-Length: " << std::dec << req.length() << __CRLF + << "User-Agent: " << RTMP_SIG_SRS_NAME << RTMP_SIG_SRS_VERSION << __CRLF + << "Content-Type: text/html" << __CRLF + << __CRLF << req; SrsSocket skt(stfd); @@ -375,13 +378,13 @@ int SrsHttpClient::parse_response_body_data(SrsHttpUri* uri, SrsSocket* skt, std int SrsHttpClient::on_headers_complete(http_parser* parser) { SrsHttpClient* obj = (SrsHttpClient*)parser->data; - obj->comple_header(parser); + obj->complete_header(parser); // see http_parser.c:1570, return 1 to skip body. return 1; } -void SrsHttpClient::comple_header(http_parser* parser) +void SrsHttpClient::complete_header(http_parser* parser) { // save the parser status when header parse completed. memcpy(&http_header, parser, sizeof(http_header)); diff --git a/trunk/src/app/srs_app_http.hpp b/trunk/src/app/srs_app_http.hpp index 97e4cb49a..e58e166d2 100644 --- a/trunk/src/app/srs_app_http.hpp +++ b/trunk/src/app/srs_app_http.hpp @@ -35,18 +35,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace srs { // CR = - const static char CR = '\r'; + #define __CR "\r" // 0x0D // LF = - const static char LF = '\n'; + #define __LF "\n" // 0x0A // SP = - const static char SP = ' '; + #define __SP " " // 0x20 // HT = - const static char HT = 9; - + #define __HT "\x09" // 0x09 + // 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). - const static char* CRLF = "\r\n"; + #define __CRLF __CR""__LF // 0x0D0A }; #ifdef SRS_HTTP_CALLBACK @@ -58,9 +58,6 @@ class SrsSocket; #include -#define SRS_HTTP_HEADER_BUFFER 1024 -#define SRS_HTTP_BODY_BUFFER 32 * 1024 - /** * used to resolve the http uri. */ @@ -124,7 +121,7 @@ private: virtual int parse_response_body_data(SrsHttpUri* uri, SrsSocket* skt, std::string* response, size_t body_left, const void* buf, size_t size); private: static int on_headers_complete(http_parser* parser); - virtual void comple_header(http_parser* parser); + virtual void complete_header(http_parser* parser); }; /** diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index 76b23b438..f22ec8055 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -25,6 +25,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include + +#define SRS_HTTP_HEADER_BUFFER 1024 SrsHttpConn::SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd) : SrsConnection(srs_server, client_stfd) @@ -44,13 +47,151 @@ int SrsHttpConn::do_cycle() return ret; } srs_trace("http get peer ip success. ip=%s", ip); + + // setup http parser + http_parser_settings settings; + + memset(&settings, 0, sizeof(settings)); + settings.on_message_begin = on_message_begin; + settings.on_url = on_url; + settings.on_header_field = on_header_field; + settings.on_header_value = on_header_value; + settings.on_headers_complete = on_headers_complete; + settings.on_body = on_body; + settings.on_message_complete = on_message_complete; + + http_parser parser; + http_parser_init(&parser, HTTP_REQUEST); + // callback object ptr. + parser.data = (void*)this; + + // underlayer socket + SrsSocket skt(stfd); + + for (;;) { + if ((ret = process_request(&skt, &parser, &settings)) != ERROR_SUCCESS) { + if (!srs_is_client_gracefully_close(ret)) { + srs_error("http client cycle failed. ret=%d", ret); + } + return ret; + } + } + + return ret; +} + +int SrsHttpConn::process_request(SrsSocket* skt, http_parser* parser, http_parser_settings* settings) +{ + int ret = ERROR_SUCCESS; + + // reset response header. + http_header = NULL; + + // parser header. + char buf[SRS_HTTP_HEADER_BUFFER]; + for (;;) { + ssize_t nread; + if ((ret = skt->read(buf, (size_t)sizeof(buf), &nread)) != ERROR_SUCCESS) { + if (!srs_is_client_gracefully_close(ret)) { + srs_error("read body from server failed. ret=%d", ret); + } + return ret; + } + + ssize_t nparsed = http_parser_execute(parser, settings, buf, nread); + srs_info("read_size=%d, nparsed=%d", (int)nread, (int)nparsed); + + // check header size. + if (http_header) { + int nb_body = nread - nparsed; + + 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); + } + + if (nparsed != nread) { + ret = ERROR_HTTP_PARSE_HEADER; + srs_error("parse response error, parsed(%d)!=read(%d), ret=%d", (int)nparsed, (int)nread, ret); + return ret; + } + } + + return ret; +} + +int SrsHttpConn::complete_header(SrsSocket* skt, http_parser* header, char* body, int nb_body) +{ + 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~"; - st_write(stfd, data, sizeof(data), -1); + skt->write(data, sizeof(data), NULL); + return ret; } + +int SrsHttpConn::on_message_begin(http_parser* parser) +{ + SrsHttpConn* obj = (SrsHttpConn*)parser->data; + (void)obj; + srs_trace("***MESSAGE BEGIN***"); + return 0; +} + +int SrsHttpConn::on_headers_complete(http_parser* parser) +{ + SrsHttpConn* obj = (SrsHttpConn*)parser->data; + (void)obj; + srs_trace("***HEADERS COMPLETE***"); + + // see http_parser.c:1570, return 1 to skip body. + return 0; +} + +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; + 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); + return 0; +} + +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); + return 0; +} + +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); + 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); + return 0; +} diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index 7ce104d77..e94edf48a 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -33,13 +33,30 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include + +class SrsSocket; + class SrsHttpConn : public SrsConnection { +private: + http_parser* http_header; 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); +private: + static int on_message_begin(http_parser* parser); + static int on_headers_complete(http_parser* parser); + static int on_message_complete(http_parser* parser); + static int on_url(http_parser* parser, const char* at, size_t length); + static int on_header_field(http_parser* parser, const char* at, size_t length); + static int on_header_value(http_parser* parser, const char* at, size_t length); + static int on_body(http_parser* parser, const char* at, size_t length); }; #endif diff --git a/trunk/src/app/srs_app_socket.cpp b/trunk/src/app/srs_app_socket.cpp index d7cfa80af..0ca479715 100644 --- a/trunk/src/app/srs_app_socket.cpp +++ b/trunk/src/app/srs_app_socket.cpp @@ -99,23 +99,26 @@ int SrsSocket::read(const void* buf, size_t size, ssize_t* nread) { int ret = ERROR_SUCCESS; - *nread = st_read(stfd, (void*)buf, size, recv_timeout); + ssize_t nb_read = st_read(stfd, (void*)buf, size, recv_timeout); + if (nread) { + *nread = nb_read; + } // On success a non-negative integer indicating the number of bytes actually read is returned // (a value of 0 means the network connection is closed or end of file is reached). - if (*nread <= 0) { + if (nb_read <= 0) { if (errno == ETIME) { return ERROR_SOCKET_TIMEOUT; } - if (*nread == 0) { + if (nb_read == 0) { errno = ECONNRESET; } return ERROR_SOCKET_READ; } - recv_bytes += *nread; + recv_bytes += nb_read; return ret; } @@ -124,23 +127,26 @@ int SrsSocket::read_fully(const void* buf, size_t size, ssize_t* nread) { int ret = ERROR_SUCCESS; - *nread = st_read_fully(stfd, (void*)buf, size, recv_timeout); + ssize_t nb_read = st_read_fully(stfd, (void*)buf, size, recv_timeout); + if (nread) { + *nread = nb_read; + } // On success a non-negative integer indicating the number of bytes actually read is returned // (a value less than nbyte means the network connection is closed or end of file is reached) - if (*nread != (ssize_t)size) { + if (nb_read != (ssize_t)size) { if (errno == ETIME) { return ERROR_SOCKET_TIMEOUT; } - if (*nread >= 0) { + if (nb_read >= 0) { errno = ECONNRESET; } return ERROR_SOCKET_READ_FULLY; } - recv_bytes += *nread; + recv_bytes += nb_read; return ret; } @@ -149,9 +155,12 @@ int SrsSocket::write(const void* buf, size_t size, ssize_t* nwrite) { int ret = ERROR_SUCCESS; - *nwrite = st_write(stfd, (void*)buf, size, send_timeout); + ssize_t nb_write = st_write(stfd, (void*)buf, size, send_timeout); + if (nwrite) { + *nwrite = nb_write; + } - if (*nwrite <= 0) { + if (nb_write <= 0) { if (errno == ETIME) { return ERROR_SOCKET_TIMEOUT; } @@ -159,7 +168,7 @@ int SrsSocket::write(const void* buf, size_t size, ssize_t* nwrite) return ERROR_SOCKET_WRITE; } - send_bytes += *nwrite; + send_bytes += nb_write; return ret; } @@ -168,9 +177,12 @@ int SrsSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite) { int ret = ERROR_SUCCESS; - *nwrite = st_writev(stfd, iov, iov_size, send_timeout); + ssize_t nb_write = st_writev(stfd, iov, iov_size, send_timeout); + if (nwrite) { + *nwrite = nb_write; + } - if (*nwrite <= 0) { + if (nb_write <= 0) { if (errno == ETIME) { return ERROR_SOCKET_TIMEOUT; } @@ -178,7 +190,7 @@ int SrsSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite) return ERROR_SOCKET_WRITE; } - send_bytes += *nwrite; + send_bytes += nb_write; return ret; } diff --git a/trunk/src/app/srs_app_socket.hpp b/trunk/src/app/srs_app_socket.hpp index 63e914fac..1bf65e237 100644 --- a/trunk/src/app/srs_app_socket.hpp +++ b/trunk/src/app/srs_app_socket.hpp @@ -60,8 +60,14 @@ public: virtual int get_recv_kbps(); virtual int get_send_kbps(); public: + /** + * @param nread, the actual read bytes, ignore if NULL. + */ virtual int read(const void* buf, size_t size, ssize_t* nread); virtual int read_fully(const void* buf, size_t size, ssize_t* nread); + /** + * @param nwrite, the actual write bytes, ignore if NULL. + */ virtual int write(const void* buf, size_t size, ssize_t* nwrite); virtual int writev(const iovec *iov, int iov_size, ssize_t* nwrite); }; diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 78bf1cfae..f58740bed 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR "0" #define VERSION_MINOR "9" -#define VERSION_REVISION "41" +#define VERSION_REVISION "42" #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION // server info. #define RTMP_SIG_SRS_KEY "srs"