• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_
6 #define NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_
7 
8 #include <stddef.h>
9 
10 #include <map>
11 #include <memory>
12 #include <string>
13 
14 #include "base/strings/string_piece.h"
15 #include "base/strings/string_util.h"
16 #include "net/ssl/ssl_info.h"
17 #include "third_party/abseil-cpp/absl/types/optional.h"
18 #include "url/gurl.h"
19 
20 namespace net {
21 
22 class HttpChunkedDecoder;
23 
24 namespace test_server {
25 
26 // Methods of HTTP requests supported by the test HTTP server.
27 enum HttpMethod {
28   METHOD_UNKNOWN,
29   METHOD_GET,
30   METHOD_HEAD,
31   METHOD_POST,
32   METHOD_PUT,
33   METHOD_DELETE,
34   METHOD_PATCH,
35   METHOD_CONNECT,
36   METHOD_OPTIONS,
37 };
38 
39 // Represents a HTTP request. Since it can be big, `use std::unique_ptr` to pass
40 // it instead of copying. However, the struct is copyable so tests can save and
41 // examine a HTTP request.
42 struct HttpRequest {
43   struct CaseInsensitiveStringComparator {
44     // Allow using StringPiece instead of string for `find()`.
45     using is_transparent = void;
46 
operatorHttpRequest::CaseInsensitiveStringComparator47     bool operator()(base::StringPiece left, base::StringPiece right) const {
48       return base::CompareCaseInsensitiveASCII(left, right) < 0;
49     }
50   };
51 
52   using HeaderMap =
53       std::map<std::string, std::string, CaseInsensitiveStringComparator>;
54 
55   HttpRequest();
56   HttpRequest(const HttpRequest& other);
57   ~HttpRequest();
58 
59   // Returns a GURL as a convenience to extract the path and query strings.
60   GURL GetURL() const;
61 
62   // The request target. For most methods, this will start with '/', e.g.,
63   // "/test?query=foo". If `method` is `METHOD_OPTIONS`, it may also be "*". If
64   // `method` is `METHOD_CONNECT`, it will instead be a string like
65   // "example.com:443".
66   std::string relative_url;
67   GURL base_url;
68   // The HTTP method. If unknown, this will be `METHOD_UNKNOWN` and the actual
69   // method will be in `method_string`.
70   HttpMethod method = METHOD_UNKNOWN;
71   std::string method_string;
72   std::string all_headers;
73   HeaderMap headers;
74   std::string content;
75   bool has_content = false;
76   absl::optional<SSLInfo> ssl_info;
77 };
78 
79 // Parses the input data and produces a valid HttpRequest object. If there is
80 // more than one request in one chunk, then only the first one will be parsed.
81 // The common use is as below:
82 // HttpRequestParser parser;
83 // (...)
84 // void OnDataChunkReceived(Socket* socket, const char* data, int size) {
85 //   parser.ProcessChunk(std::string(data, size));
86 //   if (parser.ParseRequest() == HttpRequestParser::ACCEPTED) {
87 //     std::unique_ptr<HttpRequest> request = parser.GetRequest();
88 //     (... process the request ...)
89 //   }
90 class HttpRequestParser {
91  public:
92   // Parsing result.
93   enum ParseResult {
94     WAITING,  // A request is not completed yet, waiting for more data.
95     ACCEPTED,  // A request has been parsed and it is ready to be processed.
96   };
97 
98   // Parser state.
99   enum State {
100     STATE_HEADERS,  // Waiting for a request headers.
101     STATE_CONTENT,  // Waiting for content data.
102     STATE_ACCEPTED,  // Request has been parsed.
103   };
104 
105   HttpRequestParser();
106 
107   HttpRequestParser(const HttpRequestParser&) = delete;
108   HttpRequestParser& operator=(const HttpRequestParser&) = delete;
109 
110   ~HttpRequestParser();
111 
112   // Adds chunk of data into the internal buffer.
113   void ProcessChunk(base::StringPiece data);
114 
115   // Parses the http request (including data - if provided).
116   // If returns ACCEPTED, then it means that the whole request has been found
117   // in the internal buffer (and parsed). After calling GetRequest(), it will be
118   // ready to parse another request.
119   ParseResult ParseRequest();
120 
121   // Retrieves parsed request. Can be only called, when the parser is in
122   // STATE_ACCEPTED state. After calling it, the parser is ready to parse
123   // another request.
124   std::unique_ptr<HttpRequest> GetRequest();
125 
126   // Returns `METHOD_UNKNOWN` if `token` is not a recognized method. Methods are
127   // case-sensitive.
128   static HttpMethod GetMethodType(base::StringPiece token);
129 
130  private:
131   // Parses headers and returns ACCEPTED if whole request was parsed. Otherwise
132   // returns WAITING.
133   ParseResult ParseHeaders();
134 
135   // Parses request's content data and returns ACCEPTED if all of it have been
136   // processed. Chunked Transfer Encoding is supported.
137   ParseResult ParseContent();
138 
139   // Fetches the next line from the buffer. Result does not contain \r\n.
140   // Returns an empty string for an empty line. It will assert if there is
141   // no line available.
142   std::string ShiftLine();
143 
144   std::unique_ptr<HttpRequest> http_request_;
145   std::string buffer_;
146   size_t buffer_position_ = 0;  // Current position in the internal buffer.
147   State state_ = STATE_HEADERS;
148   // Content length of the request currently being parsed.
149   size_t declared_content_length_ = 0;
150 
151   std::unique_ptr<HttpChunkedDecoder> chunked_decoder_;
152 };
153 
154 }  // namespace test_server
155 }  // namespace net
156 
157 #endif  // NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_
158