MORDOR_MAIN(int argc, const char * const argv[]) { try { Config::loadFromEnvironment(); StdoutStream stdoutStream; WorkerPool pool(2); if (argc == 1) { argc = 2; const char * const hyphen[] = { "", "-" }; argv = hyphen; } for (int i = 1; i < argc; ++i) { Stream::ptr inStream; std::string arg(argv[i]); if (arg == "-") { inStream.reset(new StdinStream()); } else { inStream.reset(new FileStream(arg, FileStream::READ)); } transferStream(inStream, stdoutStream); } } catch (const std::exception& ex) { std::cerr << ex.what() << std::endl; } return 0; }
Stream::ptr Connection::getStream(const GeneralHeaders &general, const EntityHeaders &entity, const std::string &method, Status status, boost::function<void()> notifyOnEof, boost::function<void()> notifyOnException, bool forRead) { MORDOR_ASSERT(hasMessageBody(general, entity, method, status)); Stream::ptr stream; if (forRead) { stream.reset(new SingleplexStream(m_stream, SingleplexStream::READ, false)); } else { stream.reset(new SingleplexStream(m_stream, SingleplexStream::WRITE, false)); } Stream::ptr baseStream(stream); for (ParameterizedList::const_reverse_iterator it(general.transferEncoding.rbegin()); it != general.transferEncoding.rend(); ++it) { if (stricmp(it->value.c_str(), "chunked") == 0) { stream.reset(new ChunkedStream(stream)); } else if (stricmp(it->value.c_str(), "deflate") == 0) { stream.reset(new ZlibStream(stream)); } else if (stricmp(it->value.c_str(), "gzip") == 0 || stricmp(it->value.c_str(), "x-gzip") == 0) { stream.reset(new GzipStream(stream)); } else if (stricmp(it->value.c_str(), "compress") == 0 || stricmp(it->value.c_str(), "x-compress") == 0) { MORDOR_ASSERT(false); } else if (stricmp(it->value.c_str(), "identity") == 0) { MORDOR_ASSERT(false); } else { MORDOR_ASSERT(false); } } if (stream != baseStream) { } else if (entity.contentLength != ~0ull) { LimitedStream::ptr limited(new LimitedStream(stream, entity.contentLength)); limited->strict(true); stream = limited; } else if (entity.contentType.type == "multipart") { // Getting stream to pass to multipart; self-delimiting } else { // Delimited by closing the connection } NotifyStream::ptr notify(new NotifyStream(stream)); stream = notify; notify->notifyOnClose = notifyOnEof; notify->notifyOnEof = notifyOnEof; notify->notifyOnException = notifyOnException; return stream; }
void Config::request(ServerRequest::ptr request, Access access) { const std::string &method = request->request().requestLine.method; if (method == POST) { if (access != READWRITE) { respondError(request, FORBIDDEN); return; } if (request->request().entity.contentType.type != "application" || request->request().entity.contentType.subtype != "x-www-form-urlencoded") { respondError(request, UNSUPPORTED_MEDIA_TYPE); return; } Stream::ptr requestStream = request->requestStream(); requestStream.reset(new LimitedStream(requestStream, 65536)); MemoryStream requestBody; transferStream(requestStream, requestBody); std::string queryString; queryString.resize(requestBody.buffer().readAvailable()); requestBody.buffer().copyOut(&queryString[0], requestBody.buffer().readAvailable()); bool failed = false; URI::QueryString qs(queryString); for (URI::QueryString::const_iterator it = qs.begin(); it != qs.end(); ++it) { ConfigVarBase::ptr var = Mordor::Config::lookup(it->first); if (var && !var->fromString(it->second)) failed = true; } if (failed) { respondError(request, HTTP::FORBIDDEN, "One or more new values were not accepted"); return; } // Fall through } if (method == GET || method == HEAD || method == POST) { Format format = HTML; URI::QueryString qs; if (request->request().requestLine.uri.queryDefined()) qs = request->request().requestLine.uri.queryString(); URI::QueryString::const_iterator it = qs.find("alt"); if (it != qs.end() && it->second == "json") format = JSON; // TODO: use Accept to indicate JSON switch (format) { case HTML: { request->response().status.status = OK; request->response().entity.contentType = MediaType("text", "html"); if (method == HEAD) { if (request->request().requestLine.ver == Version(1, 1) && isAcceptable(request->request().request.te, "chunked", true)) { request->response().general.transferEncoding.push_back("chunked"); } return; } Stream::ptr response = request->responseStream(); response.reset(new BufferedStream(response)); response->write("<html><body><table>\n", 20); Mordor::Config::visit(boost::bind(access == READWRITE ? &eachConfigVarHTMLWrite : &eachConfigVarHTML, _1, response)); response->write("</table></body></html>", 22); response->close(); break; } case JSON: { JSON::Object root; Mordor::Config::visit(boost::bind(&eachConfigVarJSON, _1, boost::ref(root))); std::ostringstream os; os << root; std::string str = os.str(); request->response().status.status = OK; request->response().entity.contentType = MediaType("application", "json"); request->response().entity.contentLength = str.size(); if (method != HEAD) { request->responseStream()->write(str.c_str(), str.size()); request->responseStream()->close(); } break; } default: MORDOR_NOTREACHED(); } } else { respondError(request, METHOD_NOT_ALLOWED); } }