Home | History | Annotate | Download | only in webdriver
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CHROME_TEST_WEBDRIVER_WEBDRIVER_DISPATCH_H_
      6 #define CHROME_TEST_WEBDRIVER_WEBDRIVER_DISPATCH_H_
      7 
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/basictypes.h"
     12 #include "chrome/test/webdriver/commands/response.h"
     13 #include "third_party/mongoose/mongoose.h"
     14 
     15 namespace base {
     16 class DictionaryValue;
     17 class WaitableEvent;
     18 }
     19 
     20 namespace webdriver {
     21 
     22 class Command;
     23 class HttpResponse;
     24 
     25 namespace mongoose {
     26 
     27 typedef void (HttpCallback)(struct mg_connection* connection,
     28                             const struct mg_request_info* request_info,
     29                             void* user_data);
     30 
     31 struct CallbackDetails {
     32   CallbackDetails() {
     33   }
     34 
     35   CallbackDetails(const std::string &uri_regex,
     36                   HttpCallback* func,
     37                   void* user_data)
     38     : uri_regex_(uri_regex),
     39       func_(func),
     40       user_data_(user_data) {
     41   }
     42 
     43   std::string uri_regex_;
     44   HttpCallback* func_;
     45   void* user_data_;
     46 };
     47 
     48 }  // namespace mongoose
     49 
     50 namespace internal {
     51 
     52 // Converts a |Response| into a |HttpResponse| to be returned to the client.
     53 // This function is exposed for testing.
     54 void PrepareHttpResponse(const Response& command_response,
     55                          HttpResponse* const http_response);
     56 
     57 // Sends a |response| to a WebDriver command back to the client.
     58 // |connection| is the communication pipe to the HTTP server and
     59 // |request_info| contains any data sent by the user.
     60 void SendResponse(struct mg_connection* const connection,
     61                   const std::string& request_method,
     62                   const Response& response);
     63 
     64 // Parses the request info and returns whether parsing was successful. If not,
     65 // |response| has been modified with the error.
     66 bool ParseRequestInfo(const struct mg_request_info* const request_info,
     67                       struct mg_connection* const connection,
     68                       std::string* method,
     69                       std::vector<std::string>* path_segments,
     70                       base::DictionaryValue** parameters,
     71                       Response* const response);
     72 
     73 // Allows the bulk of the implementation of |Dispatch| to be moved out of this
     74 // header file. Takes ownership of |command|.
     75 void DispatchHelper(Command* const command,
     76                     const std::string& method,
     77                     Response* const response);
     78 
     79 }  // namespace internal
     80 
     81 // Template function for dispatching commands sent to the WebDriver REST
     82 // service. |CommandType| must be a subtype of |webdriver::Command|.
     83 template<typename CommandType>
     84 void Dispatch(struct mg_connection* connection,
     85               const struct mg_request_info* request_info,
     86               void* user_data) {
     87   std::string method;
     88   std::vector<std::string> path_segments;
     89   base::DictionaryValue* parameters = NULL;
     90   Response response;
     91   if (internal::ParseRequestInfo(request_info,
     92                                  connection,
     93                                  &method,
     94                                  &path_segments,
     95                                  &parameters,
     96                                  &response)) {
     97     internal::DispatchHelper(
     98         new CommandType(path_segments, parameters),
     99         method,
    100         &response);
    101   }
    102   internal::SendResponse(connection,
    103                          request_info->request_method,
    104                          response);
    105 }
    106 
    107 class Dispatcher {
    108  public:
    109   // Creates a new dispatcher that will register all URL callbacks with the
    110   // given |context|. Each callback's pattern will be prefixed with the provided
    111   // |root|.
    112   explicit Dispatcher(const std::string& root);
    113   ~Dispatcher();
    114 
    115   bool ProcessHttpRequest(struct mg_connection* conn,
    116                           const struct mg_request_info* request_info);
    117 
    118   // Registers a callback for a WebDriver command using the given URL |pattern|.
    119   // The |CommandType| must be a subtype of |webdriver::Command|.
    120   template<typename CommandType>
    121   void Add(const std::string& pattern);
    122 
    123   // Registers a callback that will shutdown the server.  When any HTTP request
    124   // is received at this URL |pattern|, the |shutdown_event| will be signaled.
    125   void AddShutdown(const std::string& pattern,
    126                    base::WaitableEvent* shutdown_event);
    127 
    128   // Registers a callback that responds to with this server's status
    129   // information, as defined by the WebDriver wire protocol:
    130   // http://code.google.com/p/selenium/wiki/JsonWireProtocol#GET_/status.
    131   void AddStatus(const std::string& pattern);
    132 
    133   // Registers a callback for the given pattern that will return the current
    134   // WebDriver log contents.
    135   void AddLog(const std::string& pattern);
    136 
    137   // Registers a callback that will always respond with a
    138   // "HTTP/1.1 501 Not Implemented" message.
    139   void SetNotImplemented(const std::string& pattern);
    140 
    141   // Registers a callback that will respond for all other requests with a
    142   // "HTTP/1.1 403 Forbidden" message. Should be called only after registering
    143   // other callbacks.
    144   void ForbidAllOtherRequests();
    145 
    146  private:
    147   void AddCallback(const std::string& uri_pattern,
    148                    webdriver::mongoose::HttpCallback callback,
    149                    void* user_data);
    150 
    151   std::vector<webdriver::mongoose::CallbackDetails> callbacks_;
    152   const std::string url_base_;
    153 
    154   DISALLOW_COPY_AND_ASSIGN(Dispatcher);
    155 };
    156 
    157 
    158 template <typename CommandType>
    159 void Dispatcher::Add(const std::string& pattern) {
    160   AddCallback(url_base_ + pattern, &Dispatch<CommandType>, NULL);
    161 }
    162 
    163 }  // namespace webdriver
    164 
    165 #endif  // CHROME_TEST_WEBDRIVER_WEBDRIVER_DISPATCH_H_
    166