# # # patch "cmd_scgi.cc" # from [5c90b4a62489274184aa09143475be6b0023a930] # to [fa6eb8f78f0d8cdc1cef76e3066de46817e106cd] # # patch "http.cc" # from [fa7a0679195ed9d461ab9ea0826b1516ad262644] # to [2ce019878ca2f7c91032a258ec3f7fea6e662f9c] # # patch "http.hh" # from [4e2113742fb5f3d34d0ee800aca448262194e35c] # to [21674bc90c635de6b300d5b995adfa1180cbdcaa] # # patch "http_client.cc" # from [4aed572910a76dd286a7dc66780746c15d36f551] # to [2494c0fe6eabec24a68b93ef117acea90cb34d04] # ============================================================ --- cmd_scgi.cc 5c90b4a62489274184aa09143475be6b0023a930 +++ cmd_scgi.cc fa6eb8f78f0d8cdc1cef76e3066de46817e106cd @@ -91,12 +91,14 @@ namespace scgi connection(std::iostream & io) : http::connection(io) {} virtual ~connection() {} - string version() + string + version() { return scgi::version; } - bool read(string & value) + bool + read(string & value) { while (io.good()) { @@ -108,16 +110,20 @@ namespace scgi return io.good(); } - bool read(http::request & r) + http::status::code + read(http::request & r) { size_t len; - if (!http::connection::read(len, ":")) return false; + if (!http::connection::read(len, ":")) + return http::status::bad_request; + L(FL("read scgi netstring length: %d") % len); while (len > 0) { string key, val; - if (!read(key)) return false; - if (!read(val)) return false; + if (!read(key) || !read(val)) + return http::status::bad_request; + len -= key.size(); len -= val.size(); len -= 2; @@ -139,11 +145,15 @@ namespace scgi L(FL("read scgi request: %s %s %s") % r.method % r.uri % r.version); // this is a loose interpretation of the scgi "spec" - if (r.version != scgi::version) return false; - if (r.headers.find("Content-Length") == r.headers.end()) return false; + if (r.version != scgi::version) + return http::status::not_implemented; - if (!io.good()) return false; + if (r.headers.find("Content-Length") == r.headers.end()) + return http::status::length_required; + if (!io.good()) + return http::status::bad_request; + char comma = static_cast(io.get()); return http::connection::read_body(r); @@ -367,8 +377,9 @@ process_request(database & db, http::con http::request request; http::response response; - // 411 Length Required -- this should be in the reader - if (connection.read(request)) + http::status::code status = connection.read(request); + + if (status == http::status::ok) { try { @@ -443,12 +454,12 @@ process_request(database & db, http::con } else { - response.status = http::status::bad_request; + response.status = status; } response.version = connection.version(); response.headers["Status"] = - lexical_cast(response.status.code) + " " + response.status.message; + lexical_cast(response.status.value) + " " + response.status.message; response.headers["Content-Length"] = lexical_cast(response.body.size()); // Connection: close ?!? ============================================================ --- http.cc fa7a0679195ed9d461ab9ea0826b1516ad262644 +++ http.cc 2ce019878ca2f7c91032a258ec3f7fea6e662f9c @@ -28,18 +28,22 @@ namespace http return http::version; } - bool + status::code connection::read(request & r) { - bool good = - read(r.method, " ") && - read(r.uri, " ") && - read(r.version, "\r\n"); - - if (good) - L(FL("read http request: %s %s %s") % r.method % r.uri % r.version); - - return good && read_headers(r) && read_body(r); + if (!read(r.method, " ") || + !read(r.uri, " ") || + !read(r.version, "\r\n")) + return status::bad_request; + + L(FL("read http request: %s %s %s") % r.method % r.uri % r.version); + + status::code s = read_headers(r); + + if (s != status::ok) + return s; + else + return read_body(r); } void @@ -54,27 +58,31 @@ namespace http write_body(r); } - bool + status::code connection::read(response & r) { - bool good = - read(r.version, " ") && - read(r.status.code, " ") && - read(r.status.message, "\r\n"); + if (!read(r.version, " ") || + !read(r.status.value, " ") || + !read(r.status.message, "\r\n")) + return status::bad_request; - if (good) - L(FL("read http response: %s %s %s") - % r.version % r.status.code % r.status.message); + L(FL("read http response: %s %s %s") + % r.version % r.status.value % r.status.message); - return good && read_headers(r) && read_body(r); + status::code s = read_headers(r); + + if (s != status::ok) + return s; + else + return read_body(r); } void connection::write(response const & r) { - L(FL("write http response: %s %s %s") % r.version % r.status.code % r.status.message); + L(FL("write http response: %s %s %s") % r.version % r.status.value % r.status.message); write(r.version, " "); - write(r.status.code, " "); + write(r.status.value, " "); write(r.status.message, "\r\n"); write_headers(r); @@ -117,15 +125,15 @@ namespace http io << value << end; } - bool + status::code connection::read_headers(message & m) { m.headers.clear(); while (io.good() && io.peek() != '\r') { string key, val; - if (!read(key, ": ")) return false; - if (!read(val, "\r\n")) return false; + if (!read(key, ": ") || !read(val, "\r\n")) + return status::bad_request; m.headers[key] = val; @@ -134,24 +142,23 @@ namespace http L(FL("read http header end")); - if (!io.good()) return false; + if (!io.good()) + return status::bad_request; char cr = static_cast(io.get()); char lf = static_cast(io.get()); - return cr == '\r' && lf == '\n'; - + if (cr == '\r' && lf == '\n') + return status::ok; + else + return status::bad_request; } - bool + status::code connection::read_body(message & m) { if (m.headers.find("Content-Length") == m.headers.end()) - { - L(FL("missing content length header")); - // FIXME return 411 Length Required here - return false; - } + return status::length_required; size_t length = lexical_cast(m.headers["Content-Length"]); L(FL("reading http body: %d bytes") % length); @@ -170,7 +177,10 @@ namespace http L(FL("%s") % m.body); - return (length == 0); + if (length == 0) + return status::ok; + else + return status::bad_request; } void ============================================================ --- http.hh 4e2113742fb5f3d34d0ee800aca448262194e35c +++ http.hh 21674bc90c635de6b300d5b995adfa1180cbdcaa @@ -24,27 +24,34 @@ namespace http namespace status { - struct value + struct code { - value() : code(0), message("") {} - value(size_t code, std::string const message) : code(code), message(message) {} - size_t code; + code() : value(0), message("") {} + code(size_t value, std::string const message) : value(value), message(message) {} + size_t value; std::string message; - bool operator==(value const & other) const + bool operator==(code const & other) const { - return code == other.code; + return value == other.value; } + + bool operator!=(code const & other) const + { + return value != other.value; + } }; - static const value ok(200, "OK"); + static const code ok(200, "OK"); - static const value bad_request(400, "Bad Request"); - static const value not_found(404, "Not Found"); - static const value method_not_allowed(405, "Method Not Allowed"); - static const value not_acceptable(406, "Not Acceptable"); + static const code bad_request(400, "Bad Request"); + static const code not_found(404, "Not Found"); + static const code method_not_allowed(405, "Method Not Allowed"); + static const code not_acceptable(406, "Not Acceptable"); + static const code length_required(411, "Length Required"); - static const value internal_server_error(500, "Internal Server Error"); + static const code internal_server_error(500, "Internal Server Error"); + static const code not_implemented(501, "Not Implemented"); } typedef std::map header_map; @@ -74,7 +81,7 @@ namespace http struct response : public message { std::string version; - status::value status; + status::code status; }; class connection @@ -84,23 +91,23 @@ namespace http virtual ~connection() {}; virtual std::string version(); - virtual bool read(request & r); + virtual status::code read(request & r); void write(request const & r); - bool read(response & r); + status::code read(response & r); virtual void write(response const & r); protected: std::iostream & io; bool read(std::string & value, std::string const & end); - bool read(size_t & value, std::string const & end); + bool read(size_t & value, std::string const & end); void write(std::string const & value, std::string const & end); virtual void write(size_t const value, std::string const & end); - bool read_headers(message & m); - bool read_body(message & m); + status::code read_headers(message & m); + status::code read_body(message & m); void write_headers(message const & m); void write_body(message const & m); ============================================================ --- http_client.cc 4aed572910a76dd286a7dc66780746c15d36f551 +++ http_client.cc 2494c0fe6eabec24a68b93ef117acea90cb34d04 @@ -51,11 +51,7 @@ using Netxx::Timeout; using Netxx::Netbuf; using Netxx::Timeout; -using Netxx::StreamBase; -using Netxx::Stream; -using Netxx::PipeStream; - http_client::http_client(options & opts, lua_hooks & lua, netsync_connection_info const & info) : opts(opts), @@ -63,7 +59,7 @@ http_client::http_client(options & opts, info(info), stream(build_stream_to_server(opts, lua, info, info.client.u.parse_port(constants::default_http_port), - Netxx::Timeout(static_cast( + Timeout(static_cast( constants::netsync_timeout_seconds)))), nb(new Netbuf(*stream)), io(new iostream(&(*nb))), @@ -84,7 +80,7 @@ http_client::execute(http::request const L(FL("reopening connection")); stream = build_stream_to_server(opts, lua, info, info.client.u.parse_port(constants::default_http_port), - Netxx::Timeout(static_cast( + Timeout(static_cast( constants::netsync_timeout_seconds))); nb = shared_ptr< Netbuf >( new Netbuf(*stream)); @@ -97,10 +93,13 @@ http_client::execute(http::request const I(io); I(open); - // the uri in this request is relative to the server uri and needs to be adjusted + // the uri in this request is relative to the server uri and needs to be + // adjusted + http::connection connection(*io); - P(F("http request: %s %s %s") % request.method % request.uri % request.version); + P(F("http request: %s %s %s") + % request.method % request.uri % request.version); connection.write(request); @@ -115,9 +114,10 @@ http_client::execute(http::request const // FIXME: this should really attempt to pipeline several requests - I(connection.read(response)); + I(connection.read(response) == http::status::ok); - P(F("http response: %s %d %s") % response.version % response.status.code % response.status.message); + P(F("http response: %s %d %s") + % response.version % response.status.value % response.status.message); if (io->good()) L(FL("connection is good")); @@ -152,9 +152,8 @@ http_client::execute(http::request const } E(response.status == http::status::ok, origin::network, - // E(response.status_code == 200, origin::network, F("request failed: %s %d %s") - % response.version % response.status.code % response.status.message); + % response.version % response.status.value % response.status.message); } /////////////////////////////////////////////////////////////////////