Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(604)

Side by Side Diff: mojo/examples/http_server/http_server.cc

Issue 684543003: Move //mojo/examples to //examples (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/examples/http_server/BUILD.gn ('k') | mojo/examples/keyboard/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 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 #include <stdio.h>
6 #include <arpa/inet.h>
7
8 #include "base/bind.h"
9 #include "base/memory/weak_ptr.h"
10 #include "mojo/common/handle_watcher.h"
11 #include "mojo/public/c/system/main.h"
12 #include "mojo/public/cpp/application/application_delegate.h"
13 #include "mojo/public/cpp/application/application_impl.h"
14 #include "mojo/public/cpp/application/application_runner.h"
15 #include "mojo/public/cpp/system/data_pipe.h"
16 #include "mojo/services/public/interfaces/network/network_service.mojom.h"
17
18 namespace mojo {
19 namespace examples {
20
21 // The canned response that this server replies to each request with.
22 const char kResponse[] =
23 "HTTP/1.0 200 OK\n"
24 "Content-Type: text/html; charset=utf-8\n"
25 "\n"
26 "Hello, world\n";
27
28 // Represents one connection to a client. This connection will manage its own
29 // lifetime and will delete itself when the connection is closed.
30 class Connection {
31 public:
32 Connection(TCPConnectedSocketPtr conn,
33 ScopedDataPipeProducerHandle sender,
34 ScopedDataPipeConsumerHandle receiver)
35 : connection_(conn.Pass()),
36 sender_(sender.Pass()),
37 receiver_(receiver.Pass()),
38 weak_ptr_factory_(this),
39 response_(kResponse),
40 response_offset_(0) {
41 WriteMore();
42 }
43
44 ~Connection() {
45 }
46
47 private:
48 void OnSenderReady(MojoResult result) {
49 WriteMore();
50 }
51
52 void WriteMore() {
53 uint32_t num_bytes =
54 static_cast<uint32_t>(response_.size() - response_offset_);
55 // TODO(brettw) write chunks (ideally capped at some small size to
56 // illustrate how it works even in the presence of our relatively small
57 // reply) rather than specifying ALL_OR_NONE. See below.
58 MojoResult result = WriteDataRaw(
59 sender_.get(), &response_[response_offset_], &num_bytes,
60 MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
61 if (result == MOJO_RESULT_SHOULD_WAIT) {
62 num_bytes = 0;
63 } else if (result != MOJO_RESULT_OK) {
64 printf("Error writing to pipe.\n");
65 delete this;
66 return;
67 }
68
69 response_offset_ += num_bytes;
70
71 if (response_offset_ == response_.size()) {
72 // Connection complete.
73 delete this;
74 return;
75 }
76
77 // Wait for sender to be writable.
78 // TODO(brettw) we won't actually get here since we ALL_OR_NONE was
79 // specified above. This call won't work because the message loop is not a
80 // Chromium message loop. Instead, we probably need to use
81 // Environment::GetDefaultAsyncWaiter to wait on the handles and remove the
82 // ALL_OR_NONE flag.
83 sender_watcher_.Start(
84 sender_.get(),
85 MOJO_HANDLE_SIGNAL_WRITABLE, MOJO_DEADLINE_INDEFINITE,
86 base::Bind(&Connection::OnSenderReady, weak_ptr_factory_.GetWeakPtr()));
87 }
88
89 TCPConnectedSocketPtr connection_;
90 ScopedDataPipeProducerHandle sender_;
91 ScopedDataPipeConsumerHandle receiver_;
92
93 base::WeakPtrFactory<Connection> weak_ptr_factory_;
94 common::HandleWatcher sender_watcher_;
95
96 std::string response_;
97 size_t response_offset_;
98 };
99
100 class HttpServerApp : public ApplicationDelegate {
101 public:
102 virtual void Initialize(ApplicationImpl* app) override {
103 app->ConnectToService("mojo:network_service", &network_service_);
104 Start();
105 }
106
107 private:
108 void OnSocketBound(NetworkErrorPtr err, NetAddressPtr bound_address) {
109 if (err->code != 0) {
110 printf("Bound err = %d\n", err->code);
111 return;
112 }
113
114 printf("Got address %d.%d.%d.%d:%d\n",
115 (int)bound_address->ipv4->addr[0],
116 (int)bound_address->ipv4->addr[1],
117 (int)bound_address->ipv4->addr[2],
118 (int)bound_address->ipv4->addr[3],
119 (int)bound_address->ipv4->port);
120 }
121
122 void OnSocketListening(NetworkErrorPtr err) {
123 if (err->code != 0) {
124 printf("Listen err = %d\n", err->code);
125 return;
126 }
127 printf("Waiting for incoming connections...\n");
128 }
129
130 void OnConnectionAccepted(NetworkErrorPtr err, NetAddressPtr remote_address) {
131 if (err->code != 0) {
132 printf("Accepted socket error = %d\n", err->code);
133 return;
134 }
135
136 new Connection(pending_connected_socket_.Pass(),
137 pending_send_handle_.Pass(),
138 pending_receive_handle_.Pass());
139
140 // Ready for another connection.
141 WaitForNextConnection();
142 }
143
144 void WaitForNextConnection() {
145 // Need two pipes (one for each direction).
146 ScopedDataPipeConsumerHandle send_consumer_handle;
147 MojoResult result = CreateDataPipe(
148 nullptr, &pending_send_handle_, &send_consumer_handle);
149 assert(result == MOJO_RESULT_OK);
150
151 ScopedDataPipeProducerHandle receive_producer_handle;
152 result = CreateDataPipe(
153 nullptr, &receive_producer_handle, &pending_receive_handle_);
154 assert(result == MOJO_RESULT_OK);
155 MOJO_ALLOW_UNUSED_LOCAL(result);
156
157 server_socket_->Accept(send_consumer_handle.Pass(),
158 receive_producer_handle.Pass(),
159 GetProxy(&pending_connected_socket_),
160 base::Bind(&HttpServerApp::OnConnectionAccepted,
161 base::Unretained(this)));
162 }
163
164 void Start() {
165 NetAddressPtr net_address(NetAddress::New());
166 net_address->family = NET_ADDRESS_FAMILY_IPV4;
167 net_address->ipv4 = NetAddressIPv4::New();
168 net_address->ipv4->addr.resize(4);
169 net_address->ipv4->addr[0] = 127;
170 net_address->ipv4->addr[1] = 0;
171 net_address->ipv4->addr[2] = 0;
172 net_address->ipv4->addr[3] = 1;
173 net_address->ipv4->port = 0;
174
175 // Note that we can start using the proxies right away even thought the
176 // callbacks have not been called yet. If a previous step fails, they'll
177 // all fail.
178 network_service_->CreateTCPBoundSocket(
179 net_address.Pass(),
180 GetProxy(&bound_socket_),
181 base::Bind(&HttpServerApp::OnSocketBound, base::Unretained(this)));
182 bound_socket_->StartListening(GetProxy(
183 &server_socket_),
184 base::Bind(&HttpServerApp::OnSocketListening, base::Unretained(this)));
185 WaitForNextConnection();
186 }
187
188 NetworkServicePtr network_service_;
189 TCPBoundSocketPtr bound_socket_;
190 TCPServerSocketPtr server_socket_;
191
192 ScopedDataPipeProducerHandle pending_send_handle_;
193 ScopedDataPipeConsumerHandle pending_receive_handle_;
194 TCPConnectedSocketPtr pending_connected_socket_;
195 };
196
197 } // namespace examples
198 } // namespace mojo
199
200 MojoResult MojoMain(MojoHandle shell_handle) {
201 mojo::ApplicationRunner runner(new mojo::examples::HttpServerApp);
202 return runner.Run(shell_handle);
203 }
OLDNEW
« no previous file with comments | « mojo/examples/http_server/BUILD.gn ('k') | mojo/examples/keyboard/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698