summaryrefslogtreecommitdiffstats
path: root/chrome/test/webdriver/webdriver_dispatch.h
blob: 5aa5a73e35194dfdd6c306badb1b459e33827120 (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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_TEST_WEBDRIVER_WEBDRIVER_DISPATCH_H_
#define CHROME_TEST_WEBDRIVER_WEBDRIVER_DISPATCH_H_

#include <string>
#include <vector>

#include "base/basictypes.h"
#include "chrome/test/webdriver/commands/response.h"
#include "third_party/mongoose/mongoose.h"

namespace base {
class DictionaryValue;
class WaitableEvent;
}

namespace webdriver {

class Command;
class HttpResponse;

namespace mongoose {

typedef void (HttpCallback)(struct mg_connection* connection,
                            const struct mg_request_info* request_info,
                            void* user_data);

struct CallbackDetails {
  CallbackDetails() {
  }

  CallbackDetails(const std::string &uri_regex,
                  HttpCallback* func,
                  void* user_data)
    : uri_regex_(uri_regex),
      func_(func),
      user_data_(user_data) {
  }

  std::string uri_regex_;
  HttpCallback* func_;
  void* user_data_;
};

}  // namespace mongoose

namespace internal {

// Converts a |Response| into a |HttpResponse| to be returned to the client.
// This function is exposed for testing.
void PrepareHttpResponse(const Response& command_response,
                         HttpResponse* const http_response);

// Sends a |response| to a WebDriver command back to the client.
// |connection| is the communication pipe to the HTTP server and
// |request_info| contains any data sent by the user.
void SendResponse(struct mg_connection* const connection,
                  const std::string& request_method,
                  const Response& response);

// Parses the request info and returns whether parsing was successful. If not,
// |response| has been modified with the error.
bool ParseRequestInfo(const struct mg_request_info* const request_info,
                      struct mg_connection* const connection,
                      std::string* method,
                      std::vector<std::string>* path_segments,
                      base::DictionaryValue** parameters,
                      Response* const response);

// Allows the bulk of the implementation of |Dispatch| to be moved out of this
// header file. Takes ownership of |command|.
void DispatchHelper(Command* const command,
                    const std::string& method,
                    Response* const response);

}  // namespace internal

// Template function for dispatching commands sent to the WebDriver REST
// service. |CommandType| must be a subtype of |webdriver::Command|.
template<typename CommandType>
void Dispatch(struct mg_connection* connection,
              const struct mg_request_info* request_info,
              void* user_data) {
  std::string method;
  std::vector<std::string> path_segments;
  base::DictionaryValue* parameters = NULL;
  Response response;
  if (internal::ParseRequestInfo(request_info,
                                 connection,
                                 &method,
                                 &path_segments,
                                 &parameters,
                                 &response)) {
    internal::DispatchHelper(
        new CommandType(path_segments, parameters),
        method,
        &response);
  }
  internal::SendResponse(connection,
                         request_info->request_method,
                         response);
}

class Dispatcher {
 public:
  // Creates a new dispatcher that will register all URL callbacks with the
  // given |context|. Each callback's pattern will be prefixed with the provided
  // |root|.
  explicit Dispatcher(const std::string& root);
  ~Dispatcher();

  bool ProcessHttpRequest(struct mg_connection* conn,
                          const struct mg_request_info* request_info);

  // Registers a callback for a WebDriver command using the given URL |pattern|.
  // The |CommandType| must be a subtype of |webdriver::Command|.
  template<typename CommandType>
  void Add(const std::string& pattern);

  // Registers a callback that will shutdown the server.  When any HTTP request
  // is received at this URL |pattern|, the |shutdown_event| will be signaled.
  void AddShutdown(const std::string& pattern,
                   base::WaitableEvent* shutdown_event);

  // Registers a callback that responds to with this server's status
  // information, as defined by the WebDriver wire protocol:
  // http://code.google.com/p/selenium/wiki/JsonWireProtocol#GET_/status.
  void AddStatus(const std::string& pattern);

  // Registers a callback for the given pattern that will return the current
  // WebDriver log contents.
  void AddLog(const std::string& pattern);

  // Registers a callback that will always respond with a
  // "HTTP/1.1 501 Not Implemented" message.
  void SetNotImplemented(const std::string& pattern);

  // Registers a callback that will respond for all other requests with a
  // "HTTP/1.1 403 Forbidden" message. Should be called only after registering
  // other callbacks.
  void ForbidAllOtherRequests();

 private:
  void AddCallback(const std::string& uri_pattern,
                   webdriver::mongoose::HttpCallback callback,
                   void* user_data);

  std::vector<webdriver::mongoose::CallbackDetails> callbacks_;
  const std::string url_base_;

  DISALLOW_COPY_AND_ASSIGN(Dispatcher);
};


template <typename CommandType>
void Dispatcher::Add(const std::string& pattern) {
  AddCallback(url_base_ + pattern, &Dispatch<CommandType>, NULL);
}

}  // namespace webdriver

#endif  // CHROME_TEST_WEBDRIVER_WEBDRIVER_DISPATCH_H_