aboutsummaryrefslogtreecommitdiff
path: root/brep/repository-root.cxx
blob: 180d61ffc9770e4abdbb55d18465218647923551 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// file      : brep/repository-root.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#include <brep/repository-root>

#include <map>
#include <functional>

#include <web/module>

#include <brep/types>
#include <brep/utility>
#include <brep/package-search>
#include <brep/repository-details>

using namespace std;

namespace brep
{
  // request_proxy
  //
  class request_proxy: public request
  {
  public:
    request_proxy (request& r, const name_values& p)
        : request_ (r), parameters_ (p) {}

    virtual const path_type&
    path () {return request_.path ();}

    virtual const name_values&
    parameters () {return parameters_;}

    virtual const name_values&
    cookies () {return request_.cookies ();}

    virtual istream&
    content () {return request_.content ();}

  private:
    request& request_;
    const name_values& parameters_;
  };

  // repository_root
  //
  void repository_root::
  handle (request& rq, response& rs)
  {
    MODULE_DIAG;

    // Dispatch request handling to the appropriate module depending on the
    // function name passed as a first HTTP request parameter. The parameter
    // should have no value specified. If no function name is passed,
    // the default handler is selected. Example: cppget.org/?about
    //

    string func;
    name_values params (rq.parameters ());

    // Obtain the function name.
    //
    if (!params.empty () && !params.front ().value)
    {
      func = move (params.front ().name);

      // Cleanup not to confuse the selected handler with the unknown parameter.
      //
      params.erase (params.begin ());
    }

    // To handle the request a new module instance is created as a copy of
    // the corresponsing exemplar.
    //
    using module_ptr = unique_ptr<module>;

    // Function name to module factory map.
    //
    const map<string, function<module_ptr()>>
      handlers ({
        {
          "about",
          [this]() -> module_ptr
          {return module_ptr (new repository_details (repository_details_));}
        },
        {
          string (), // The default handler.
          [this]() -> module_ptr
          {return module_ptr (new package_search (package_search_));}
        }});

    // Find proper handler.
    //
    auto i (handlers.find (func));
    if (i == handlers.end ())
      throw invalid_request (400, "unknown function");

    module_ptr m (i->second ());
    if (m->loaded ())
    {
      // Delegate request handling.
      //
      // @@ An exception thrown by the handler will be attributed to the
      //    repository-root service while being logged. Could intercept
      //    exception handling to fix that, but let's not complicate the
      //    code for the time being.
      //
      //
      request_proxy rqp (rq, params);
      m->handle (rqp, rs);
    }
    else
      // The module is not loaded, presumably being disabled in the web server
      // configuration file.
      //
      throw invalid_request (404, "handler not available");
  }
}