summaryrefslogtreecommitdiff
path: root/chromium/net/test/embedded_test_server/http_request_unittest.cc
blob: d0e534f4e0a73ef6d4db436412f1220c3bb4d3cc (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
// 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.

#include "net/test/embedded_test_server/http_request.h"

#include <memory>

#include "testing/gtest/include/gtest/gtest.h"

namespace net {
namespace test_server {

TEST(HttpRequestTest, ParseRequest) {
  HttpRequestParser parser;

  // Process request in chunks to check if the parser deals with border cases.
  // Also, check multi-line headers as well as multiple requests in the same
  // chunk. This basically should cover all the simplest border cases.
  parser.ProcessChunk("POST /foobar.html HTTP/1.1\r\n");
  EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
  parser.ProcessChunk("Host: localhost:1234\r\n");
  EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
  parser.ProcessChunk("Multi-line-header: abcd\r\n");
  EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
  parser.ProcessChunk(" efgh\r\n");
  EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
  parser.ProcessChunk(" ijkl\r\n");
  EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
  parser.ProcessChunk("Content-Length: 10\r\n\r\n");
  EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
  // Content data and another request in the same chunk (possible in http/1.1).
  parser.ProcessChunk("1234567890GET /another.html HTTP/1.1\r\n\r\n");
  ASSERT_EQ(HttpRequestParser::ACCEPTED, parser.ParseRequest());

  // Fetch the first request and validate it.
  {
    std::unique_ptr<HttpRequest> request = parser.GetRequest();
    EXPECT_EQ("/foobar.html", request->relative_url);
    EXPECT_EQ("POST", request->method_string);
    EXPECT_EQ(METHOD_POST, request->method);
    EXPECT_EQ("1234567890", request->content);
    ASSERT_EQ(3u, request->headers.size());

    EXPECT_EQ(1u, request->headers.count("Host"));
    EXPECT_EQ(1u, request->headers.count("Multi-line-header"));
    EXPECT_EQ(1u, request->headers.count("Content-Length"));

    const char kExpectedAllHeaders[] =
        "POST /foobar.html HTTP/1.1\r\n"
        "Host: localhost:1234\r\n"
        "Multi-line-header: abcd\r\n"
        " efgh\r\n"
        " ijkl\r\n"
        "Content-Length: 10\r\n";
    EXPECT_EQ(kExpectedAllHeaders, request->all_headers);
    EXPECT_EQ("localhost:1234", request->headers["Host"]);
    EXPECT_EQ("abcd efgh ijkl", request->headers["Multi-line-header"]);
    EXPECT_EQ("10", request->headers["Content-Length"]);
  }

  // No other request available yet since we do not support multiple requests
  // per connection.
  EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
}

TEST(HttpRequestTest, ParseRequestWithEmptyBody) {
  HttpRequestParser parser;

  parser.ProcessChunk("POST /foobar.html HTTP/1.1\r\n");
  parser.ProcessChunk("Content-Length: 0\r\n\r\n");
  ASSERT_EQ(HttpRequestParser::ACCEPTED, parser.ParseRequest());

  std::unique_ptr<HttpRequest> request = parser.GetRequest();
  EXPECT_EQ("", request->content);
  EXPECT_TRUE(request->has_content);
  EXPECT_EQ(1u, request->headers.count("Content-Length"));
  EXPECT_EQ("0", request->headers["Content-Length"]);
}

TEST(HttpRequestTest, ParseRequestWithChunkedBody) {
  HttpRequestParser parser;

  parser.ProcessChunk("POST /foobar.html HTTP/1.1\r\n");
  parser.ProcessChunk("Transfer-Encoding: chunked\r\n\r\n");
  parser.ProcessChunk("5\r\nhello\r\n");
  parser.ProcessChunk("1\r\n \r\n");
  parser.ProcessChunk("5\r\nworld\r\n");
  parser.ProcessChunk("0\r\n\r\n");
  ASSERT_EQ(HttpRequestParser::ACCEPTED, parser.ParseRequest());

  std::unique_ptr<HttpRequest> request = parser.GetRequest();
  EXPECT_EQ("hello world", request->content);
  EXPECT_TRUE(request->has_content);
  EXPECT_EQ(1u, request->headers.count("Transfer-Encoding"));
  EXPECT_EQ("chunked", request->headers["Transfer-Encoding"]);
}

TEST(HttpRequestTest, ParseRequestWithChunkedBodySlow) {
  HttpRequestParser parser;

  parser.ProcessChunk("POST /foobar.html HTTP/1.1\r\n");
  parser.ProcessChunk("Transfer-Encoding: chunked\r\n\r\n");
  std::string chunked_body = "5\r\nhello\r\n0\r\n\r\n";

  // Send one character at a time, and make the parser parse the request.
  for (size_t i = 0; i < chunked_body.size(); i++) {
    parser.ProcessChunk(chunked_body.substr(i, 1));
    // Except for the last pass, ParseRequest() should give WAITING.
    if (i != chunked_body.size() - 1) {
      ASSERT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
    }
  }
  // All chunked data has been sent, the last ParseRequest should give ACCEPTED.
  ASSERT_EQ(HttpRequestParser::ACCEPTED, parser.ParseRequest());
  std::unique_ptr<HttpRequest> request = parser.GetRequest();
  EXPECT_EQ("hello", request->content);
  EXPECT_TRUE(request->has_content);
  EXPECT_EQ(1u, request->headers.count("Transfer-Encoding"));
  EXPECT_EQ("chunked", request->headers["Transfer-Encoding"]);
}

TEST(HttpRequestTest, ParseRequestWithoutBody) {
  HttpRequestParser parser;

  parser.ProcessChunk("POST /foobar.html HTTP/1.1\r\n\r\n");
  ASSERT_EQ(HttpRequestParser::ACCEPTED, parser.ParseRequest());

  std::unique_ptr<HttpRequest> request = parser.GetRequest();
  EXPECT_EQ("", request->content);
  EXPECT_FALSE(request->has_content);
}

TEST(HttpRequestTest, ParseGet) {
  HttpRequestParser parser;

  parser.ProcessChunk("GET /foobar.html HTTP/1.1\r\n\r\n");
  ASSERT_EQ(HttpRequestParser::ACCEPTED, parser.ParseRequest());

  std::unique_ptr<HttpRequest> request = parser.GetRequest();
  EXPECT_EQ("/foobar.html", request->relative_url);
  EXPECT_EQ("GET", request->method_string);
  EXPECT_EQ(METHOD_GET, request->method);
  EXPECT_EQ("", request->content);
  EXPECT_FALSE(request->has_content);
}

TEST(HttpRequestTest, GetURL) {
  HttpRequest request;
  request.relative_url = "/foobar.html?q=foo";
  request.base_url = GURL("https://127.0.0.1:8080");
  EXPECT_EQ("https://127.0.0.1:8080/foobar.html?q=foo",
            request.GetURL().spec());
}

TEST(HttpRequestTest, GetURLFallback) {
  HttpRequest request;
  request.relative_url = "/foobar.html?q=foo";
  EXPECT_EQ("http://localhost/foobar.html?q=foo", request.GetURL().spec());
}

}  // namespace test_server
}  // namespace net