blob: 299e9335ae0793cf6564beef781916e8542e61ab [file] [log] [blame]
Andreea Costinas054fbb52020-06-12 20:46:22 +02001// Copyright 2020 The Chromium OS 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#include "system-proxy/test_http_server.h"
6
7#include <netinet/in.h>
8#include <sys/socket.h>
9#include <sys/types.h>
10
11#include <base/bind.h>
Andreea Costinas054fbb52020-06-12 20:46:22 +020012#include <base/callback_helpers.h>
13#include <base/strings/stringprintf.h>
14#include <chromeos/patchpanel/net_util.h>
15#include <chromeos/patchpanel/socket.h>
16
17namespace {
18constexpr int kMaxConn = 10;
19
20const std::string_view kConnectionEstablished =
21 "HTTP/1.1 200 Connection established\r\n\r\n";
22
23const std::string_view kProxyAuthenticationRequiredBasic =
24 "HTTP/1.1 407 Proxy Authentication Required\r\n"
25 "Proxy-Authenticate: Basic realm=\"My Proxy\"\r\n"
26 "\r\n";
27
28const std::string_view kProxyAuthenticationRequiredNegotiate =
29 "HTTP/1.1 407 Proxy Authentication Required\r\n"
30 "Proxy-Authenticate: Negotiate realm=\"My Proxy\"\r\n"
31 "\r\n";
32
Andreea Costinasf90a4c02020-06-12 22:30:51 +020033const std::string_view kHttpBadGateway =
Andreea Costinascc4d54e2020-10-19 15:46:25 +020034 "HTTP/1.1 502 Bad Gateway\r\n\r\nBad gateway message from the server";
Andreea Costinas054fbb52020-06-12 20:46:22 +020035
36} // namespace
37namespace system_proxy {
38
39HttpTestServer::HttpTestServer()
40 : base::SimpleThread("HttpTestServer"),
41 listening_addr_(htonl(INADDR_LOOPBACK)),
42 listening_port_(0) {}
43
44HttpTestServer::~HttpTestServer() {
45 if (!HasBeenStarted()) {
46 return;
47 }
48 int fd = listening_socket_->release();
49 if (close(fd) != 0) {
Andreea-Elena Costinasfae5c152020-09-28 18:18:31 +000050 LOG(ERROR) << "Failed to close the listening socket";
Andreea Costinas054fbb52020-06-12 20:46:22 +020051 }
52 Join();
53}
54
55void HttpTestServer::Run() {
56 struct sockaddr_storage client_src = {};
57 socklen_t sockaddr_len = sizeof(client_src);
58 while (!expected_responses_.empty()) {
59 if (auto client_conn = listening_socket_->Accept(
60 (struct sockaddr*)&client_src, &sockaddr_len)) {
Andreea-Elena Costinasfae5c152020-09-28 18:18:31 +000061 std::string_view server_reply =
62 GetConnectReplyString(expected_responses_.front());
Andreea Costinas054fbb52020-06-12 20:46:22 +020063 expected_responses_.pop();
Andreea Costinas054fbb52020-06-12 20:46:22 +020064 client_conn->SendTo(server_reply.data(), server_reply.size());
65 }
66 }
67}
68
69void HttpTestServer::BeforeStart() {
70 listening_socket_ =
71 std::make_unique<patchpanel::Socket>(AF_INET, SOCK_STREAM);
72
73 struct sockaddr_in addr = {0};
74 addr.sin_family = AF_INET;
75 addr.sin_port = htons(listening_port_);
76 addr.sin_addr.s_addr = listening_addr_;
77 if (!listening_socket_->Bind((const struct sockaddr*)&addr, sizeof(addr))) {
78 LOG(ERROR) << "Cannot bind source socket" << std::endl;
79 return;
80 }
81
82 if (!listening_socket_->Listen(kMaxConn)) {
83 LOG(ERROR) << "Cannot listen on source socket." << std::endl;
84 return;
85 }
86
87 socklen_t len = sizeof(addr);
88 if (getsockname(listening_socket_->fd(), (struct sockaddr*)&addr, &len)) {
89 LOG(ERROR) << "Cannot get the listening port " << std::endl;
90 return;
91 }
92 listening_port_ = ntohs(addr.sin_port);
93}
94
95std::string HttpTestServer::GetUrl() {
96 return base::StringPrintf(
97 "http://%s:%d", patchpanel::IPv4AddressToString(listening_addr_).c_str(),
98 listening_port_);
99}
100
Andreea Costinas054fbb52020-06-12 20:46:22 +0200101void HttpTestServer::AddHttpConnectReply(HttpConnectReply reply) {
102 expected_responses_.push(reply);
103}
104
105std::string_view HttpTestServer::GetConnectReplyString(HttpConnectReply reply) {
106 switch (reply) {
107 case HttpConnectReply::kOk:
108 return kConnectionEstablished;
109 case HttpConnectReply::kAuthRequiredBasic:
110 return kProxyAuthenticationRequiredBasic;
111 case HttpConnectReply::kAuthRequiredKerberos:
112 return kProxyAuthenticationRequiredNegotiate;
113 case HttpConnectReply::kBadGateway:
114 return kHttpBadGateway;
115 default:
116 return kConnectionEstablished;
117 }
118}
119
120} // namespace system_proxy