diff --git a/trunk/src/app/srs_app_http.cpp b/trunk/src/app/srs_app_http.cpp index 54d04400e..56c399e90 100644 --- a/trunk/src/app/srs_app_http.cpp +++ b/trunk/src/app/srs_app_http.cpp @@ -34,6 +34,7 @@ using namespace std; #include #include #include +#include #define SRS_DEFAULT_HTTP_PORT 80 @@ -85,10 +86,39 @@ int SrsHttpHandler::process_request(SrsSocket* skt, SrsHttpMessage* req) if (req->method() == HTTP_OPTIONS) { return res_options(skt); } + + int status_code; + std::string reason_phrase; + if (!is_handler_valid(req, status_code, reason_phrase)) { + std::stringstream ss; + + ss << JOBJECT_START + << JFIELD_ERROR(ERROR_HTTP_HANDLER_INVALID) << JFIELD_CONT + << JFIELD_ORG("data", JOBJECT_START) + << JFIELD_ORG("status_code", status_code) << JFIELD_CONT + << JFIELD_STR("reason_phrase", reason_phrase) << JFIELD_CONT + << JFIELD_STR("url", req->url()) + << JOBJECT_END + << JOBJECT_END; + + return res_error(skt, status_code, reason_phrase, ss.str()); + } return do_process_request(skt, req); } +bool SrsHttpHandler::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase) +{ + if (!req->match()->unmatched_url.empty()) { + status_code = HTTP_NotFound; + reason_phrase = HTTP_NotFound_str; + + return false; + } + + return true; +} + int SrsHttpHandler::do_process_request(SrsSocket* /*skt*/, SrsHttpMessage* /*req*/) { int ret = ERROR_SUCCESS; @@ -156,6 +186,11 @@ int SrsHttpHandler::best_match(const char* path, int length, SrsHttpHandlerMatch (*ppmatch)->handler = handler; (*ppmatch)->matched_url.append(match_start, match_length); + int unmatch_length = length - match_length; + if (unmatch_length > 0) { + (*ppmatch)->unmatched_url.append(match_start + match_length, unmatch_length); + } + return ret; } @@ -166,6 +201,13 @@ SrsHttpHandler* SrsHttpHandler::res_status_line(std::stringstream& ss) return this; } +SrsHttpHandler* SrsHttpHandler::res_status_line_error(std::stringstream& ss, int code, std::string reason_phrase) +{ + ss << "HTTP/1.1 " << code << " " << reason_phrase << __CRLF + << "Server: SRS/"RTMP_SIG_SRS_VERSION"" << __CRLF; + return this; +} + SrsHttpHandler* SrsHttpHandler::res_content_type(std::stringstream& ss) { ss << "Content-Type: text/html;charset=utf-8" << __CRLF @@ -248,6 +290,22 @@ int SrsHttpHandler::res_json(SrsSocket* skt, std::string json) return res_flush(skt, ss); } +int SrsHttpHandler::res_error(SrsSocket* skt, int code, std::string reason_phrase, std::string body) +{ + std::stringstream ss; + + ss << "HTTP/1.1 " << code << " " << reason_phrase << __CRLF + << "Server: SRS/"RTMP_SIG_SRS_VERSION"" << __CRLF; + + res_status_line_error(ss, code, reason_phrase) + ->res_content_type_json(ss) + ->res_content_length(ss, (int)body.length()) + ->res_header_eof(ss) + ->res_body(ss, body); + + return res_flush(skt, ss); +} + SrsHttpHandler* SrsHttpHandler::create_http_api() { return new SrsApiRoot(); diff --git a/trunk/src/app/srs_app_http.hpp b/trunk/src/app/srs_app_http.hpp index a4a913d8a..fdb1969fb 100644 --- a/trunk/src/app/srs_app_http.hpp +++ b/trunk/src/app/srs_app_http.hpp @@ -62,6 +62,89 @@ class SrsHttpHandler; #define __CRLF "\r\n" // 0x0D0A #define __CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A +// 6.1.1 Status Code and Reason Phrase +#define HTTP_Continue 100 +#define HTTP_SwitchingProtocols 101 +#define HTTP_OK 200 +#define HTTP_Created 201 +#define HTTP_Accepted 202 +#define HTTP_NonAuthoritativeInformation 203 +#define HTTP_NoContent 204 +#define HTTP_ResetContent 205 +#define HTTP_PartialContent 206 +#define HTTP_MultipleChoices 300 +#define HTTP_MovedPermanently 301 +#define HTTP_Found 302 +#define HTTP_SeeOther 303 +#define HTTP_NotModified 304 +#define HTTP_UseProxy 305 +#define HTTP_TemporaryRedirect 307 +#define HTTP_BadRequest 400 +#define HTTP_Unauthorized 401 +#define HTTP_PaymentRequired 402 +#define HTTP_Forbidden 403 +#define HTTP_NotFound 404 +#define HTTP_MethodNotAllowed 405 +#define HTTP_NotAcceptable 406 +#define HTTP_ProxyAuthenticationRequired 407 +#define HTTP_RequestTimeout 408 +#define HTTP_Conflict 409 +#define HTTP_Gone 410 +#define HTTP_LengthRequired 411 +#define HTTP_PreconditionFailed 412 +#define HTTP_RequestEntityTooLarge 413 +#define HTTP_RequestURITooLarge 414 +#define HTTP_UnsupportedMediaType 415 +#define HTTP_RequestedRangeNotSatisfiable 416 +#define HTTP_ExpectationFailed 417 +#define HTTP_InternalServerError 500 +#define HTTP_NotImplemented 501 +#define HTTP_BadGateway 502 +#define HTTP_ServiceUnavailable 503 +#define HTTP_GatewayTimeout 504 +#define HTTP_HTTPVersionNotSupported 505 + +#define HTTP_Continue_str "Continue" +#define HTTP_SwitchingProtocols_str "Switching Protocols" +#define HTTP_OK_str "OK" +#define HTTP_Created_str "Created " +#define HTTP_Accepted_str "Accepted" +#define HTTP_NonAuthoritativeInformation_str "Non Authoritative Information " +#define HTTP_NoContent_str "No Content " +#define HTTP_ResetContent_str "Reset Content" +#define HTTP_PartialContent_str "Partial Content" +#define HTTP_MultipleChoices_str "Multiple Choices " +#define HTTP_MovedPermanently_str "Moved Permanently" +#define HTTP_Found_str "Found" +#define HTTP_SeeOther_str "See Other" +#define HTTP_NotModified_str "Not Modified " +#define HTTP_UseProxy_str "Use Proxy" +#define HTTP_TemporaryRedirect_str "Temporary Redirect " +#define HTTP_BadRequest_str "Bad Request" +#define HTTP_Unauthorized_str "Unauthorized" +#define HTTP_PaymentRequired_str "Payment Required " +#define HTTP_Forbidden_str "Forbidden " +#define HTTP_NotFound_str "Not Found" +#define HTTP_MethodNotAllowed_str "Method Not Allowed" +#define HTTP_NotAcceptable_str "Not Acceptable " +#define HTTP_ProxyAuthenticationRequired_str "Proxy Authentication Required " +#define HTTP_RequestTimeout_str "Request Timeout" +#define HTTP_Conflict_str "Conflict" +#define HTTP_Gone_str "Gone" +#define HTTP_LengthRequired_str "Length Required" +#define HTTP_PreconditionFailed_str "Precondition Failed" +#define HTTP_RequestEntityTooLarge_str "Request Entity Too Large " +#define HTTP_RequestURITooLarge_str "Request URI Too Large" +#define HTTP_UnsupportedMediaType_str "Unsupported Media Type" +#define HTTP_RequestedRangeNotSatisfiable_str "Requested Range Not Satisfiable" +#define HTTP_ExpectationFailed_str "Expectation Failed " +#define HTTP_InternalServerError_str "Internal Server Error " +#define HTTP_NotImplemented_str "Not Implemented" +#define HTTP_BadGateway_str "Bad Gateway" +#define HTTP_ServiceUnavailable_str "Service Unavailable" +#define HTTP_GatewayTimeout_str "Gateway Timeout" +#define HTTP_HTTPVersionNotSupported_str "HTTP Version Not Supported" + // linux path seprator #define __PATH_SEP '/' // query string seprator @@ -86,6 +169,7 @@ class SrsHttpHandlerMatch public: SrsHttpHandler* handler; std::string matched_url; + std::string unmatched_url; public: SrsHttpHandlerMatch(); }; @@ -127,10 +211,22 @@ public: virtual int best_match(const char* path, int length, SrsHttpHandlerMatch** ppmatch); // factory methods protected: + /** + * check whether the handler is valid. + * for example, user access /apis, actually it's not found, + * we will find the root handler to process it. + * @remark user can override this method, and should invoke it first. + * @see SrsApiRoot::is_handler_valid + */ + virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase); + /** + * do the actual process of request. + */ virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); // response writer public: virtual SrsHttpHandler* res_status_line(std::stringstream& ss); + virtual SrsHttpHandler* res_status_line_error(std::stringstream& ss, int code, std::string reason_phrase); virtual SrsHttpHandler* res_content_type(std::stringstream& ss); virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss); virtual SrsHttpHandler* res_content_length(std::stringstream& ss, int64_t length); @@ -142,6 +238,7 @@ public: virtual int res_options(SrsSocket* skt); virtual int res_text(SrsSocket* skt, std::string body); virtual int res_json(SrsSocket* skt, std::string json); + virtual int res_error(SrsSocket* skt, int code, std::string reason_phrase, std::string body); // object creator public: /** diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 4d239d5a6..bc97b25d2 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -44,6 +44,21 @@ SrsApiRoot::~SrsApiRoot() { } +bool SrsApiRoot::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase) +{ + if (!SrsHttpHandler::is_handler_valid(req, status_code, reason_phrase)) { + return false; + } + + if (req->match()->matched_url.length() != 1) { + status_code = HTTP_NotFound; + reason_phrase = HTTP_NotFound_str; + return false; + } + + return true; +} + bool SrsApiRoot::can_handle(const char* path, int length, const char** pchild) { // reset the child path to path, diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index bb549950b..bb4f50a93 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -48,6 +48,7 @@ public: SrsApiRoot(); virtual ~SrsApiRoot(); public: + virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase); virtual bool can_handle(const char* path, int length, const char** pchild); virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); }; diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index c2a520f39..c898e32f3 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -158,6 +158,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ERROR_HTTP_DATA_INVLIAD 801 #define ERROR_HTTP_PARSE_HEADER 802 #define ERROR_HTTP_HANDLER_MATCH_URL 803 +#define ERROR_HTTP_HANDLER_INVALID 804 // system control message, // not an error, but special control logic.