OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * |
| 3 * Copyright 2015-2016, Google Inc. |
| 4 * All rights reserved. |
| 5 * |
| 6 * Redistribution and use in source and binary forms, with or without |
| 7 * modification, are permitted provided that the following conditions are |
| 8 * met: |
| 9 * |
| 10 * * Redistributions of source code must retain the above copyright |
| 11 * notice, this list of conditions and the following disclaimer. |
| 12 * * Redistributions in binary form must reproduce the above |
| 13 * copyright notice, this list of conditions and the following disclaimer |
| 14 * in the documentation and/or other materials provided with the |
| 15 * distribution. |
| 16 * * Neither the name of Google Inc. nor the names of its |
| 17 * contributors may be used to endorse or promote products derived from |
| 18 * this software without specific prior written permission. |
| 19 * |
| 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 * |
| 32 */ |
| 33 |
| 34 #include "src/core/httpcli/httpcli.h" |
| 35 #include "src/core/iomgr/sockaddr.h" |
| 36 |
| 37 #include <string.h> |
| 38 |
| 39 #include <grpc/support/alloc.h> |
| 40 #include <grpc/support/log.h> |
| 41 #include <grpc/support/string_util.h> |
| 42 |
| 43 #include "src/core/httpcli/format_request.h" |
| 44 #include "src/core/httpcli/parser.h" |
| 45 #include "src/core/iomgr/endpoint.h" |
| 46 #include "src/core/iomgr/iomgr_internal.h" |
| 47 #include "src/core/iomgr/resolve_address.h" |
| 48 #include "src/core/iomgr/tcp_client.h" |
| 49 #include "src/core/support/string.h" |
| 50 |
| 51 typedef struct { |
| 52 gpr_slice request_text; |
| 53 grpc_httpcli_parser parser; |
| 54 grpc_resolved_addresses *addresses; |
| 55 size_t next_address; |
| 56 grpc_endpoint *ep; |
| 57 char *host; |
| 58 char *ssl_host_override; |
| 59 gpr_timespec deadline; |
| 60 int have_read_byte; |
| 61 const grpc_httpcli_handshaker *handshaker; |
| 62 grpc_httpcli_response_cb on_response; |
| 63 void *user_data; |
| 64 grpc_httpcli_context *context; |
| 65 grpc_pollset *pollset; |
| 66 grpc_iomgr_object iomgr_obj; |
| 67 gpr_slice_buffer incoming; |
| 68 gpr_slice_buffer outgoing; |
| 69 grpc_closure on_read; |
| 70 grpc_closure done_write; |
| 71 grpc_closure connected; |
| 72 } internal_request; |
| 73 |
| 74 static grpc_httpcli_get_override g_get_override = NULL; |
| 75 static grpc_httpcli_post_override g_post_override = NULL; |
| 76 |
| 77 static void plaintext_handshake(grpc_exec_ctx *exec_ctx, void *arg, |
| 78 grpc_endpoint *endpoint, const char *host, |
| 79 void (*on_done)(grpc_exec_ctx *exec_ctx, |
| 80 void *arg, |
| 81 grpc_endpoint *endpoint)) { |
| 82 on_done(exec_ctx, arg, endpoint); |
| 83 } |
| 84 |
| 85 const grpc_httpcli_handshaker grpc_httpcli_plaintext = {"http", |
| 86 plaintext_handshake}; |
| 87 |
| 88 void grpc_httpcli_context_init(grpc_httpcli_context *context) { |
| 89 context->pollset_set = grpc_pollset_set_create(); |
| 90 } |
| 91 |
| 92 void grpc_httpcli_context_destroy(grpc_httpcli_context *context) { |
| 93 grpc_pollset_set_destroy(context->pollset_set); |
| 94 } |
| 95 |
| 96 static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req); |
| 97 |
| 98 static void finish(grpc_exec_ctx *exec_ctx, internal_request *req, |
| 99 int success) { |
| 100 grpc_pollset_set_del_pollset(exec_ctx, req->context->pollset_set, |
| 101 req->pollset); |
| 102 req->on_response(exec_ctx, req->user_data, success ? &req->parser.r : NULL); |
| 103 grpc_httpcli_parser_destroy(&req->parser); |
| 104 if (req->addresses != NULL) { |
| 105 grpc_resolved_addresses_destroy(req->addresses); |
| 106 } |
| 107 if (req->ep != NULL) { |
| 108 grpc_endpoint_destroy(exec_ctx, req->ep); |
| 109 } |
| 110 gpr_slice_unref(req->request_text); |
| 111 gpr_free(req->host); |
| 112 gpr_free(req->ssl_host_override); |
| 113 grpc_iomgr_unregister_object(&req->iomgr_obj); |
| 114 gpr_slice_buffer_destroy(&req->incoming); |
| 115 gpr_slice_buffer_destroy(&req->outgoing); |
| 116 gpr_free(req); |
| 117 } |
| 118 |
| 119 static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success); |
| 120 |
| 121 static void do_read(grpc_exec_ctx *exec_ctx, internal_request *req) { |
| 122 grpc_endpoint_read(exec_ctx, req->ep, &req->incoming, &req->on_read); |
| 123 } |
| 124 |
| 125 static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { |
| 126 internal_request *req = user_data; |
| 127 size_t i; |
| 128 |
| 129 for (i = 0; i < req->incoming.count; i++) { |
| 130 if (GPR_SLICE_LENGTH(req->incoming.slices[i])) { |
| 131 req->have_read_byte = 1; |
| 132 if (!grpc_httpcli_parser_parse(&req->parser, req->incoming.slices[i])) { |
| 133 finish(exec_ctx, req, 0); |
| 134 return; |
| 135 } |
| 136 } |
| 137 } |
| 138 |
| 139 if (success) { |
| 140 do_read(exec_ctx, req); |
| 141 } else if (!req->have_read_byte) { |
| 142 next_address(exec_ctx, req); |
| 143 } else { |
| 144 finish(exec_ctx, req, grpc_httpcli_parser_eof(&req->parser)); |
| 145 } |
| 146 } |
| 147 |
| 148 static void on_written(grpc_exec_ctx *exec_ctx, internal_request *req) { |
| 149 do_read(exec_ctx, req); |
| 150 } |
| 151 |
| 152 static void done_write(grpc_exec_ctx *exec_ctx, void *arg, bool success) { |
| 153 internal_request *req = arg; |
| 154 if (success) { |
| 155 on_written(exec_ctx, req); |
| 156 } else { |
| 157 next_address(exec_ctx, req); |
| 158 } |
| 159 } |
| 160 |
| 161 static void start_write(grpc_exec_ctx *exec_ctx, internal_request *req) { |
| 162 gpr_slice_ref(req->request_text); |
| 163 gpr_slice_buffer_add(&req->outgoing, req->request_text); |
| 164 grpc_endpoint_write(exec_ctx, req->ep, &req->outgoing, &req->done_write); |
| 165 } |
| 166 |
| 167 static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, |
| 168 grpc_endpoint *ep) { |
| 169 internal_request *req = arg; |
| 170 |
| 171 if (!ep) { |
| 172 next_address(exec_ctx, req); |
| 173 return; |
| 174 } |
| 175 |
| 176 req->ep = ep; |
| 177 start_write(exec_ctx, req); |
| 178 } |
| 179 |
| 180 static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { |
| 181 internal_request *req = arg; |
| 182 |
| 183 if (!req->ep) { |
| 184 next_address(exec_ctx, req); |
| 185 return; |
| 186 } |
| 187 req->handshaker->handshake( |
| 188 exec_ctx, req, req->ep, |
| 189 req->ssl_host_override ? req->ssl_host_override : req->host, |
| 190 on_handshake_done); |
| 191 } |
| 192 |
| 193 static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) { |
| 194 grpc_resolved_address *addr; |
| 195 if (req->next_address == req->addresses->naddrs) { |
| 196 finish(exec_ctx, req, 0); |
| 197 return; |
| 198 } |
| 199 addr = &req->addresses->addrs[req->next_address++]; |
| 200 grpc_closure_init(&req->connected, on_connected, req); |
| 201 grpc_tcp_client_connect( |
| 202 exec_ctx, &req->connected, &req->ep, req->context->pollset_set, |
| 203 (struct sockaddr *)&addr->addr, addr->len, req->deadline); |
| 204 } |
| 205 |
| 206 static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, |
| 207 grpc_resolved_addresses *addresses) { |
| 208 internal_request *req = arg; |
| 209 if (!addresses) { |
| 210 finish(exec_ctx, req, 0); |
| 211 return; |
| 212 } |
| 213 req->addresses = addresses; |
| 214 req->next_address = 0; |
| 215 next_address(exec_ctx, req); |
| 216 } |
| 217 |
| 218 static void internal_request_begin( |
| 219 grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, |
| 220 grpc_pollset *pollset, const grpc_httpcli_request *request, |
| 221 gpr_timespec deadline, grpc_httpcli_response_cb on_response, |
| 222 void *user_data, const char *name, gpr_slice request_text) { |
| 223 internal_request *req = gpr_malloc(sizeof(internal_request)); |
| 224 memset(req, 0, sizeof(*req)); |
| 225 req->request_text = request_text; |
| 226 grpc_httpcli_parser_init(&req->parser); |
| 227 req->on_response = on_response; |
| 228 req->user_data = user_data; |
| 229 req->deadline = deadline; |
| 230 req->handshaker = |
| 231 request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; |
| 232 req->context = context; |
| 233 req->pollset = pollset; |
| 234 grpc_closure_init(&req->on_read, on_read, req); |
| 235 grpc_closure_init(&req->done_write, done_write, req); |
| 236 gpr_slice_buffer_init(&req->incoming); |
| 237 gpr_slice_buffer_init(&req->outgoing); |
| 238 grpc_iomgr_register_object(&req->iomgr_obj, name); |
| 239 req->host = gpr_strdup(request->host); |
| 240 req->ssl_host_override = gpr_strdup(request->ssl_host_override); |
| 241 |
| 242 grpc_pollset_set_add_pollset(exec_ctx, req->context->pollset_set, |
| 243 req->pollset); |
| 244 grpc_resolve_address(request->host, req->handshaker->default_port, |
| 245 on_resolved, req); |
| 246 } |
| 247 |
| 248 void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, |
| 249 grpc_pollset *pollset, |
| 250 const grpc_httpcli_request *request, |
| 251 gpr_timespec deadline, |
| 252 grpc_httpcli_response_cb on_response, void *user_data) { |
| 253 char *name; |
| 254 if (g_get_override && |
| 255 g_get_override(exec_ctx, request, deadline, on_response, user_data)) { |
| 256 return; |
| 257 } |
| 258 gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path); |
| 259 internal_request_begin(exec_ctx, context, pollset, request, deadline, |
| 260 on_response, user_data, name, |
| 261 grpc_httpcli_format_get_request(request)); |
| 262 gpr_free(name); |
| 263 } |
| 264 |
| 265 void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, |
| 266 grpc_pollset *pollset, |
| 267 const grpc_httpcli_request *request, |
| 268 const char *body_bytes, size_t body_size, |
| 269 gpr_timespec deadline, |
| 270 grpc_httpcli_response_cb on_response, void *user_data) { |
| 271 char *name; |
| 272 if (g_post_override && |
| 273 g_post_override(exec_ctx, request, body_bytes, body_size, deadline, |
| 274 on_response, user_data)) { |
| 275 return; |
| 276 } |
| 277 gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->path); |
| 278 internal_request_begin( |
| 279 exec_ctx, context, pollset, request, deadline, on_response, user_data, |
| 280 name, grpc_httpcli_format_post_request(request, body_bytes, body_size)); |
| 281 gpr_free(name); |
| 282 } |
| 283 |
| 284 void grpc_httpcli_set_override(grpc_httpcli_get_override get, |
| 285 grpc_httpcli_post_override post) { |
| 286 g_get_override = get; |
| 287 g_post_override = post; |
| 288 } |
OLD | NEW |