summaryrefslogtreecommitdiff
path: root/chromium/net/test/embedded_test_server/http_request.h
blob: 65b37bb26ae1aefc15c60fc29fa1889f36750b8a (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
// 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 NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_
#define NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_

#include <stddef.h>

#include <map>
#include <memory>
#include <string>

#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "net/ssl/ssl_info.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"

namespace net {

class HttpChunkedDecoder;

namespace test_server {

// Methods of HTTP requests supported by the test HTTP server.
enum HttpMethod {
  METHOD_UNKNOWN,
  METHOD_GET,
  METHOD_HEAD,
  METHOD_POST,
  METHOD_PUT,
  METHOD_DELETE,
  METHOD_PATCH,
  METHOD_CONNECT,
  METHOD_OPTIONS,
};

// Represents a HTTP request. Since it can be big, use scoped_ptr to pass it
// instead of copying. However, the struct is copyable so tests can save and
// examine a HTTP request.
struct HttpRequest {
  struct CaseInsensitiveStringComparator {
    bool operator()(const std::string& left, const std::string& right) const {
      return base::CompareCaseInsensitiveASCII(left, right) < 0;
    }
  };

  using HeaderMap =
      std::map<std::string, std::string, CaseInsensitiveStringComparator>;

  HttpRequest();
  HttpRequest(const HttpRequest& other);
  ~HttpRequest();

  // Returns a GURL as a convenience to extract the path and query strings.
  GURL GetURL() const;

  std::string relative_url;  // Starts with '/'. Example: "/test?query=foo"
  GURL base_url;
  HttpMethod method;
  std::string method_string;
  std::string all_headers;
  HeaderMap headers;
  std::string content;
  bool has_content;
  absl::optional<SSLInfo> ssl_info;
};

// Parses the input data and produces a valid HttpRequest object. If there is
// more than one request in one chunk, then only the first one will be parsed.
// The common use is as below:
// HttpRequestParser parser;
// (...)
// void OnDataChunkReceived(Socket* socket, const char* data, int size) {
//   parser.ProcessChunk(std::string(data, size));
//   if (parser.ParseRequest() == HttpRequestParser::ACCEPTED) {
//     std::unique_ptr<HttpRequest> request = parser.GetRequest();
//     (... process the request ...)
//   }
class HttpRequestParser {
 public:
  // Parsing result.
  enum ParseResult {
    WAITING,  // A request is not completed yet, waiting for more data.
    ACCEPTED,  // A request has been parsed and it is ready to be processed.
  };

  // Parser state.
  enum State {
    STATE_HEADERS,  // Waiting for a request headers.
    STATE_CONTENT,  // Waiting for content data.
    STATE_ACCEPTED,  // Request has been parsed.
  };

  HttpRequestParser();
  ~HttpRequestParser();

  // Adds chunk of data into the internal buffer.
  void ProcessChunk(const base::StringPiece& data);

  // Parses the http request (including data - if provided).
  // If returns ACCEPTED, then it means that the whole request has been found
  // in the internal buffer (and parsed). After calling GetRequest(), it will be
  // ready to parse another request.
  ParseResult ParseRequest();

  // Retrieves parsed request. Can be only called, when the parser is in
  // STATE_ACCEPTED state. After calling it, the parser is ready to parse
  // another request.
  std::unique_ptr<HttpRequest> GetRequest();

 private:
  HttpMethod GetMethodType(const std::string& token) const;

  // Parses headers and returns ACCEPTED if whole request was parsed. Otherwise
  // returns WAITING.
  ParseResult ParseHeaders();

  // Parses request's content data and returns ACCEPTED if all of it have been
  // processed. Chunked Transfer Encoding is supported.
  ParseResult ParseContent();

  // Fetches the next line from the buffer. Result does not contain \r\n.
  // Returns an empty string for an empty line. It will assert if there is
  // no line available.
  std::string ShiftLine();

  std::unique_ptr<HttpRequest> http_request_;
  std::string buffer_;
  size_t buffer_position_;  // Current position in the internal buffer.
  State state_;
  // Content length of the request currently being parsed.
  size_t declared_content_length_;

  std::unique_ptr<HttpChunkedDecoder> chunked_decoder_;

  DISALLOW_COPY_AND_ASSIGN(HttpRequestParser);
};

}  // namespace test_server
}  // namespace net

#endif  // NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_