PageRenderTime 114ms CodeModel.GetById 41ms app.highlight 34ms RepoModel.GetById 16ms app.codeStats 20ms

/mordor/http/servlets/config.cpp

http://github.com/mozy/mordor
C++ | 147 lines | 134 code | 10 blank | 3 comment | 32 complexity | 3c9139f991cabf8b120eb4d217c2cd49 MD5 | raw file
  1// Copyright (c) 2010 - Mozy, Inc.
  2
  3#include "mordor/http/servlets/config.h"
  4
  5#include "mordor/config.h"
  6#include "mordor/http/server.h"
  7#include "mordor/json.h"
  8#include "mordor/streams/buffered.h"
  9#include "mordor/streams/limited.h"
 10#include "mordor/streams/memory.h"
 11#include "mordor/streams/transfer.h"
 12
 13namespace Mordor {
 14namespace HTTP {
 15namespace Servlets {
 16
 17static void eachConfigVarHTMLWrite(ConfigVarBase::ptr var, Stream::ptr stream)
 18{
 19    std::string name = var->name();
 20    stream->write("<tr><td align=\"right\">", 22);
 21    stream->write(name.c_str(), name.size());
 22    stream->write("=</td><td><form name=\"", 22);
 23    stream->write(name.c_str(), name.size());
 24    stream->write("\" method=\"post\"><input type=\"text\" name=\"", 41);
 25    stream->write(name.c_str(), name.size());
 26    stream->write("\" value=\"", 9);
 27    std::string value = var->toString();
 28    stream->write(value.c_str(), value.size());
 29    stream->write("\" /><input type=\"submit\" value=\"Change\" /></form></td></tr>\n", 60);
 30}
 31
 32static void eachConfigVarHTML(ConfigVarBase::ptr var, Stream::ptr stream)
 33{
 34    std::string name = var->name();
 35    stream->write("<tr><td align=\"right\">", 22);
 36    stream->write(name.c_str(), name.size());
 37    stream->write("=</td><td>", 10);
 38    std::string value = var->toString();
 39    stream->write(value.c_str(), value.size());
 40    stream->write("</td></tr>\n", 11);
 41}
 42
 43static void eachConfigVarJSON(ConfigVarBase::ptr var, JSON::Object &object)
 44{
 45    object.insert(std::make_pair(var->name(), var->toString()));
 46}
 47
 48namespace {
 49enum Format {
 50    HTML,
 51    JSON
 52};
 53}
 54
 55void Config::request(ServerRequest::ptr request, Access access)
 56{
 57    const std::string &method = request->request().requestLine.method;
 58    if (method == POST) {
 59        if (access != READWRITE) {
 60            respondError(request, FORBIDDEN);
 61            return;
 62        }
 63        if (request->request().entity.contentType.type != "application" ||
 64            request->request().entity.contentType.subtype != "x-www-form-urlencoded") {
 65            respondError(request, UNSUPPORTED_MEDIA_TYPE);
 66            return;
 67        }
 68        Stream::ptr requestStream = request->requestStream();
 69        requestStream.reset(new LimitedStream(requestStream, 65536));
 70        MemoryStream requestBody;
 71        transferStream(requestStream, requestBody);
 72        std::string queryString;
 73        queryString.resize(requestBody.buffer().readAvailable());
 74        requestBody.buffer().copyOut(&queryString[0], requestBody.buffer().readAvailable());
 75
 76        bool failed = false;
 77        URI::QueryString qs(queryString);
 78        for (URI::QueryString::const_iterator it = qs.begin();
 79            it != qs.end();
 80            ++it) {
 81            ConfigVarBase::ptr var = Mordor::Config::lookup(it->first);
 82            if (var && !var->fromString(it->second))
 83                failed = true;
 84        }
 85        if (failed) {
 86            respondError(request, HTTP::FORBIDDEN,
 87                "One or more new values were not accepted");
 88            return;
 89        }
 90        // Fall through
 91    }
 92    if (method == GET || method == HEAD || method == POST) {
 93        Format format = HTML;
 94        URI::QueryString qs;
 95        if (request->request().requestLine.uri.queryDefined())
 96            qs = request->request().requestLine.uri.queryString();
 97        URI::QueryString::const_iterator it = qs.find("alt");
 98        if (it != qs.end() && it->second == "json")
 99            format = JSON;
100        // TODO: use Accept to indicate JSON
101        switch (format) {
102            case HTML:
103            {
104                request->response().status.status = OK;
105                request->response().entity.contentType = MediaType("text", "html");
106                if (method == HEAD) {
107                    if (request->request().requestLine.ver == Version(1, 1) &&
108                        isAcceptable(request->request().request.te, "chunked", true)) {
109                        request->response().general.transferEncoding.push_back("chunked");
110                    }
111                    return;
112                }
113                Stream::ptr response = request->responseStream();
114                response.reset(new BufferedStream(response));
115                response->write("<html><body><table>\n", 20);
116                Mordor::Config::visit(boost::bind(access == READWRITE ?
117                    &eachConfigVarHTMLWrite : &eachConfigVarHTML, _1,
118                    response));
119                response->write("</table></body></html>", 22);
120                response->close();
121                break;
122            }
123            case JSON:
124            {
125                JSON::Object root;
126                Mordor::Config::visit(boost::bind(&eachConfigVarJSON, _1, boost::ref(root)));
127                std::ostringstream os;
128                os << root;
129                std::string str = os.str();
130                request->response().status.status = OK;
131                request->response().entity.contentType = MediaType("application", "json");
132                request->response().entity.contentLength = str.size();
133                if (method != HEAD) {
134                    request->responseStream()->write(str.c_str(), str.size());
135                    request->responseStream()->close();
136                }
137                break;
138            }
139            default:
140                MORDOR_NOTREACHED();
141        }
142    } else {
143        respondError(request, METHOD_NOT_ALLOWED);
144    }
145}
146
147}}}