1*1270Sigor@sysoev.ru 2*1270Sigor@sysoev.ru /* 3*1270Sigor@sysoev.ru * Copyright (C) Igor Sysoev 4*1270Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 5*1270Sigor@sysoev.ru */ 6*1270Sigor@sysoev.ru 7*1270Sigor@sysoev.ru #include <nxt_router.h> 8*1270Sigor@sysoev.ru #include <nxt_http.h> 9*1270Sigor@sysoev.ru 10*1270Sigor@sysoev.ru 11*1270Sigor@sysoev.ru typedef void (*nxt_http_upstream_connect_t)(nxt_task_t *task, 12*1270Sigor@sysoev.ru nxt_http_upstream_t *upstream, nxt_http_peer_t *peer); 13*1270Sigor@sysoev.ru 14*1270Sigor@sysoev.ru 15*1270Sigor@sysoev.ru struct nxt_http_upstream_s { 16*1270Sigor@sysoev.ru uint32_t current; 17*1270Sigor@sysoev.ru uint32_t n; 18*1270Sigor@sysoev.ru uint8_t protocol; 19*1270Sigor@sysoev.ru nxt_http_upstream_connect_t connect; 20*1270Sigor@sysoev.ru nxt_sockaddr_t *sockaddr[1]; 21*1270Sigor@sysoev.ru }; 22*1270Sigor@sysoev.ru 23*1270Sigor@sysoev.ru 24*1270Sigor@sysoev.ru static void nxt_http_upstream_connect(nxt_task_t *task, 25*1270Sigor@sysoev.ru nxt_http_upstream_t *upstream, nxt_http_peer_t *peer); 26*1270Sigor@sysoev.ru static nxt_http_action_t *nxt_http_proxy_handler(nxt_task_t *task, 27*1270Sigor@sysoev.ru nxt_http_request_t *r, nxt_http_action_t *action); 28*1270Sigor@sysoev.ru static void nxt_http_proxy_header_send(nxt_task_t *task, void *obj, void *data); 29*1270Sigor@sysoev.ru static void nxt_http_proxy_header_sent(nxt_task_t *task, void *obj, void *data); 30*1270Sigor@sysoev.ru static void nxt_http_proxy_header_read(nxt_task_t *task, void *obj, void *data); 31*1270Sigor@sysoev.ru static void nxt_http_proxy_send_body(nxt_task_t *task, void *obj, void *data); 32*1270Sigor@sysoev.ru static void nxt_http_proxy_read(nxt_task_t *task, void *obj, void *data); 33*1270Sigor@sysoev.ru static void nxt_http_proxy_buf_mem_completion(nxt_task_t *task, void *obj, 34*1270Sigor@sysoev.ru void *data); 35*1270Sigor@sysoev.ru static void nxt_http_proxy_error(nxt_task_t *task, void *obj, void *data); 36*1270Sigor@sysoev.ru 37*1270Sigor@sysoev.ru 38*1270Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_proxy_header_send_state; 39*1270Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_proxy_header_sent_state; 40*1270Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_proxy_header_read_state; 41*1270Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_proxy_read_state; 42*1270Sigor@sysoev.ru 43*1270Sigor@sysoev.ru 44*1270Sigor@sysoev.ru nxt_int_t 45*1270Sigor@sysoev.ru nxt_http_proxy_create(nxt_mp_t *mp, nxt_http_action_t *action) 46*1270Sigor@sysoev.ru { 47*1270Sigor@sysoev.ru nxt_str_t name; 48*1270Sigor@sysoev.ru nxt_sockaddr_t *sa; 49*1270Sigor@sysoev.ru nxt_http_upstream_t *upstream; 50*1270Sigor@sysoev.ru 51*1270Sigor@sysoev.ru sa = NULL; 52*1270Sigor@sysoev.ru name = action->name; 53*1270Sigor@sysoev.ru 54*1270Sigor@sysoev.ru if (nxt_str_start(&name, "http://", 7)) { 55*1270Sigor@sysoev.ru name.length -= 7; 56*1270Sigor@sysoev.ru name.start += 7; 57*1270Sigor@sysoev.ru 58*1270Sigor@sysoev.ru sa = nxt_sockaddr_parse(mp, &name); 59*1270Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 60*1270Sigor@sysoev.ru return NXT_ERROR; 61*1270Sigor@sysoev.ru } 62*1270Sigor@sysoev.ru 63*1270Sigor@sysoev.ru sa->type = SOCK_STREAM; 64*1270Sigor@sysoev.ru } 65*1270Sigor@sysoev.ru 66*1270Sigor@sysoev.ru if (sa != NULL) { 67*1270Sigor@sysoev.ru upstream = nxt_mp_alloc(mp, sizeof(nxt_http_upstream_t)); 68*1270Sigor@sysoev.ru if (nxt_slow_path(upstream == NULL)) { 69*1270Sigor@sysoev.ru return NXT_ERROR; 70*1270Sigor@sysoev.ru } 71*1270Sigor@sysoev.ru 72*1270Sigor@sysoev.ru upstream->current = 0; 73*1270Sigor@sysoev.ru upstream->n = 1; 74*1270Sigor@sysoev.ru upstream->protocol = NXT_HTTP_PROTO_H1; 75*1270Sigor@sysoev.ru upstream->connect = nxt_http_upstream_connect; 76*1270Sigor@sysoev.ru upstream->sockaddr[0] = sa; 77*1270Sigor@sysoev.ru 78*1270Sigor@sysoev.ru action->u.upstream = upstream; 79*1270Sigor@sysoev.ru action->handler = nxt_http_proxy_handler; 80*1270Sigor@sysoev.ru } 81*1270Sigor@sysoev.ru 82*1270Sigor@sysoev.ru return NXT_OK; 83*1270Sigor@sysoev.ru } 84*1270Sigor@sysoev.ru 85*1270Sigor@sysoev.ru 86*1270Sigor@sysoev.ru static nxt_http_action_t * 87*1270Sigor@sysoev.ru nxt_http_proxy_handler(nxt_task_t *task, nxt_http_request_t *r, 88*1270Sigor@sysoev.ru nxt_http_action_t *action) 89*1270Sigor@sysoev.ru { 90*1270Sigor@sysoev.ru nxt_http_peer_t *peer; 91*1270Sigor@sysoev.ru 92*1270Sigor@sysoev.ru peer = nxt_mp_zalloc(r->mem_pool, sizeof(nxt_http_peer_t)); 93*1270Sigor@sysoev.ru if (nxt_slow_path(peer == NULL)) { 94*1270Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 95*1270Sigor@sysoev.ru return NULL; 96*1270Sigor@sysoev.ru } 97*1270Sigor@sysoev.ru 98*1270Sigor@sysoev.ru peer->request = r; 99*1270Sigor@sysoev.ru r->peer = peer; 100*1270Sigor@sysoev.ru 101*1270Sigor@sysoev.ru nxt_mp_retain(r->mem_pool); 102*1270Sigor@sysoev.ru 103*1270Sigor@sysoev.ru action->u.upstream->connect(task, action->u.upstream, peer); 104*1270Sigor@sysoev.ru 105*1270Sigor@sysoev.ru return NULL; 106*1270Sigor@sysoev.ru } 107*1270Sigor@sysoev.ru 108*1270Sigor@sysoev.ru 109*1270Sigor@sysoev.ru static void 110*1270Sigor@sysoev.ru nxt_http_upstream_connect(nxt_task_t *task, nxt_http_upstream_t *upstream, 111*1270Sigor@sysoev.ru nxt_http_peer_t *peer) 112*1270Sigor@sysoev.ru { 113*1270Sigor@sysoev.ru peer->protocol = upstream->protocol; 114*1270Sigor@sysoev.ru peer->sockaddr = upstream->sockaddr[0]; 115*1270Sigor@sysoev.ru 116*1270Sigor@sysoev.ru peer->request->state = &nxt_http_proxy_header_send_state; 117*1270Sigor@sysoev.ru 118*1270Sigor@sysoev.ru nxt_http_proto[peer->protocol].peer_connect(task, peer); 119*1270Sigor@sysoev.ru } 120*1270Sigor@sysoev.ru 121*1270Sigor@sysoev.ru 122*1270Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_proxy_header_send_state 123*1270Sigor@sysoev.ru nxt_aligned(64) = 124*1270Sigor@sysoev.ru { 125*1270Sigor@sysoev.ru .ready_handler = nxt_http_proxy_header_send, 126*1270Sigor@sysoev.ru .error_handler = nxt_http_proxy_error, 127*1270Sigor@sysoev.ru }; 128*1270Sigor@sysoev.ru 129*1270Sigor@sysoev.ru 130*1270Sigor@sysoev.ru static void 131*1270Sigor@sysoev.ru nxt_http_proxy_header_send(nxt_task_t *task, void *obj, void *data) 132*1270Sigor@sysoev.ru { 133*1270Sigor@sysoev.ru nxt_http_peer_t *peer; 134*1270Sigor@sysoev.ru nxt_http_request_t *r; 135*1270Sigor@sysoev.ru 136*1270Sigor@sysoev.ru r = obj; 137*1270Sigor@sysoev.ru peer = data; 138*1270Sigor@sysoev.ru r->state = &nxt_http_proxy_header_sent_state; 139*1270Sigor@sysoev.ru 140*1270Sigor@sysoev.ru nxt_http_proto[peer->protocol].peer_header_send(task, peer); 141*1270Sigor@sysoev.ru } 142*1270Sigor@sysoev.ru 143*1270Sigor@sysoev.ru 144*1270Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_proxy_header_sent_state 145*1270Sigor@sysoev.ru nxt_aligned(64) = 146*1270Sigor@sysoev.ru { 147*1270Sigor@sysoev.ru .ready_handler = nxt_http_proxy_header_sent, 148*1270Sigor@sysoev.ru .error_handler = nxt_http_proxy_error, 149*1270Sigor@sysoev.ru }; 150*1270Sigor@sysoev.ru 151*1270Sigor@sysoev.ru 152*1270Sigor@sysoev.ru static void 153*1270Sigor@sysoev.ru nxt_http_proxy_header_sent(nxt_task_t *task, void *obj, void *data) 154*1270Sigor@sysoev.ru { 155*1270Sigor@sysoev.ru nxt_http_peer_t *peer; 156*1270Sigor@sysoev.ru nxt_http_request_t *r; 157*1270Sigor@sysoev.ru 158*1270Sigor@sysoev.ru r = obj; 159*1270Sigor@sysoev.ru peer = data; 160*1270Sigor@sysoev.ru r->state = &nxt_http_proxy_header_read_state; 161*1270Sigor@sysoev.ru 162*1270Sigor@sysoev.ru nxt_http_proto[peer->protocol].peer_header_read(task, peer); 163*1270Sigor@sysoev.ru } 164*1270Sigor@sysoev.ru 165*1270Sigor@sysoev.ru 166*1270Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_proxy_header_read_state 167*1270Sigor@sysoev.ru nxt_aligned(64) = 168*1270Sigor@sysoev.ru { 169*1270Sigor@sysoev.ru .ready_handler = nxt_http_proxy_header_read, 170*1270Sigor@sysoev.ru .error_handler = nxt_http_proxy_error, 171*1270Sigor@sysoev.ru }; 172*1270Sigor@sysoev.ru 173*1270Sigor@sysoev.ru 174*1270Sigor@sysoev.ru static void 175*1270Sigor@sysoev.ru nxt_http_proxy_header_read(nxt_task_t *task, void *obj, void *data) 176*1270Sigor@sysoev.ru { 177*1270Sigor@sysoev.ru nxt_http_peer_t *peer; 178*1270Sigor@sysoev.ru nxt_http_field_t *f, *field; 179*1270Sigor@sysoev.ru nxt_http_request_t *r; 180*1270Sigor@sysoev.ru 181*1270Sigor@sysoev.ru r = obj; 182*1270Sigor@sysoev.ru peer = data; 183*1270Sigor@sysoev.ru 184*1270Sigor@sysoev.ru r->status = peer->status; 185*1270Sigor@sysoev.ru 186*1270Sigor@sysoev.ru nxt_debug(task, "http proxy status: %d", peer->status); 187*1270Sigor@sysoev.ru 188*1270Sigor@sysoev.ru nxt_list_each(field, peer->fields) { 189*1270Sigor@sysoev.ru 190*1270Sigor@sysoev.ru nxt_debug(task, "http proxy header: \"%*s: %*s\"", 191*1270Sigor@sysoev.ru (size_t) field->name_length, field->name, 192*1270Sigor@sysoev.ru (size_t) field->value_length, field->value); 193*1270Sigor@sysoev.ru 194*1270Sigor@sysoev.ru if (!field->skip) { 195*1270Sigor@sysoev.ru f = nxt_list_add(r->resp.fields); 196*1270Sigor@sysoev.ru if (nxt_slow_path(f == NULL)) { 197*1270Sigor@sysoev.ru nxt_http_proxy_error(task, r, peer); 198*1270Sigor@sysoev.ru return; 199*1270Sigor@sysoev.ru } 200*1270Sigor@sysoev.ru 201*1270Sigor@sysoev.ru *f = *field; 202*1270Sigor@sysoev.ru } 203*1270Sigor@sysoev.ru 204*1270Sigor@sysoev.ru } nxt_list_loop; 205*1270Sigor@sysoev.ru 206*1270Sigor@sysoev.ru nxt_http_request_header_send(task, r, nxt_http_proxy_send_body, peer); 207*1270Sigor@sysoev.ru } 208*1270Sigor@sysoev.ru 209*1270Sigor@sysoev.ru 210*1270Sigor@sysoev.ru static void 211*1270Sigor@sysoev.ru nxt_http_proxy_send_body(nxt_task_t *task, void *obj, void *data) 212*1270Sigor@sysoev.ru { 213*1270Sigor@sysoev.ru nxt_buf_t *out; 214*1270Sigor@sysoev.ru nxt_http_peer_t *peer; 215*1270Sigor@sysoev.ru nxt_http_request_t *r; 216*1270Sigor@sysoev.ru 217*1270Sigor@sysoev.ru r = obj; 218*1270Sigor@sysoev.ru peer = data; 219*1270Sigor@sysoev.ru out = peer->body; 220*1270Sigor@sysoev.ru 221*1270Sigor@sysoev.ru if (out != NULL) { 222*1270Sigor@sysoev.ru peer->body = NULL; 223*1270Sigor@sysoev.ru nxt_http_request_send(task, r, out); 224*1270Sigor@sysoev.ru } 225*1270Sigor@sysoev.ru 226*1270Sigor@sysoev.ru r->state = &nxt_http_proxy_read_state; 227*1270Sigor@sysoev.ru 228*1270Sigor@sysoev.ru nxt_http_proto[peer->protocol].peer_read(task, peer); 229*1270Sigor@sysoev.ru } 230*1270Sigor@sysoev.ru 231*1270Sigor@sysoev.ru 232*1270Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_proxy_read_state 233*1270Sigor@sysoev.ru nxt_aligned(64) = 234*1270Sigor@sysoev.ru { 235*1270Sigor@sysoev.ru .ready_handler = nxt_http_proxy_read, 236*1270Sigor@sysoev.ru .error_handler = nxt_http_proxy_error, 237*1270Sigor@sysoev.ru }; 238*1270Sigor@sysoev.ru 239*1270Sigor@sysoev.ru 240*1270Sigor@sysoev.ru static void 241*1270Sigor@sysoev.ru nxt_http_proxy_read(nxt_task_t *task, void *obj, void *data) 242*1270Sigor@sysoev.ru { 243*1270Sigor@sysoev.ru nxt_buf_t *out; 244*1270Sigor@sysoev.ru nxt_bool_t last; 245*1270Sigor@sysoev.ru nxt_http_peer_t *peer; 246*1270Sigor@sysoev.ru nxt_http_request_t *r; 247*1270Sigor@sysoev.ru 248*1270Sigor@sysoev.ru r = obj; 249*1270Sigor@sysoev.ru peer = data; 250*1270Sigor@sysoev.ru out = peer->body; 251*1270Sigor@sysoev.ru peer->body = NULL; 252*1270Sigor@sysoev.ru last = nxt_buf_is_last(out); 253*1270Sigor@sysoev.ru 254*1270Sigor@sysoev.ru nxt_http_request_send(task, r, out); 255*1270Sigor@sysoev.ru 256*1270Sigor@sysoev.ru if (!last) { 257*1270Sigor@sysoev.ru nxt_http_proto[peer->protocol].peer_read(task, peer); 258*1270Sigor@sysoev.ru 259*1270Sigor@sysoev.ru } else { 260*1270Sigor@sysoev.ru nxt_http_proto[peer->protocol].peer_close(task, peer); 261*1270Sigor@sysoev.ru 262*1270Sigor@sysoev.ru nxt_mp_release(r->mem_pool); 263*1270Sigor@sysoev.ru } 264*1270Sigor@sysoev.ru } 265*1270Sigor@sysoev.ru 266*1270Sigor@sysoev.ru 267*1270Sigor@sysoev.ru nxt_buf_t * 268*1270Sigor@sysoev.ru nxt_http_proxy_buf_mem_alloc(nxt_task_t *task, nxt_http_request_t *r, 269*1270Sigor@sysoev.ru size_t size) 270*1270Sigor@sysoev.ru { 271*1270Sigor@sysoev.ru nxt_buf_t *b; 272*1270Sigor@sysoev.ru 273*1270Sigor@sysoev.ru b = nxt_event_engine_buf_mem_alloc(task->thread->engine, size); 274*1270Sigor@sysoev.ru if (nxt_fast_path(b != NULL)) { 275*1270Sigor@sysoev.ru b->completion_handler = nxt_http_proxy_buf_mem_completion; 276*1270Sigor@sysoev.ru b->parent = r; 277*1270Sigor@sysoev.ru nxt_mp_retain(r->mem_pool); 278*1270Sigor@sysoev.ru 279*1270Sigor@sysoev.ru } else { 280*1270Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 281*1270Sigor@sysoev.ru } 282*1270Sigor@sysoev.ru 283*1270Sigor@sysoev.ru return b; 284*1270Sigor@sysoev.ru } 285*1270Sigor@sysoev.ru 286*1270Sigor@sysoev.ru 287*1270Sigor@sysoev.ru static void 288*1270Sigor@sysoev.ru nxt_http_proxy_buf_mem_completion(nxt_task_t *task, void *obj, void *data) 289*1270Sigor@sysoev.ru { 290*1270Sigor@sysoev.ru nxt_buf_t *b, *next; 291*1270Sigor@sysoev.ru nxt_http_peer_t *peer; 292*1270Sigor@sysoev.ru nxt_http_request_t *r; 293*1270Sigor@sysoev.ru 294*1270Sigor@sysoev.ru b = obj; 295*1270Sigor@sysoev.ru r = data; 296*1270Sigor@sysoev.ru 297*1270Sigor@sysoev.ru peer = r->peer; 298*1270Sigor@sysoev.ru 299*1270Sigor@sysoev.ru do { 300*1270Sigor@sysoev.ru next = b->next; 301*1270Sigor@sysoev.ru 302*1270Sigor@sysoev.ru nxt_http_proxy_buf_mem_free(task, r, b); 303*1270Sigor@sysoev.ru 304*1270Sigor@sysoev.ru b = next; 305*1270Sigor@sysoev.ru } while (b != NULL); 306*1270Sigor@sysoev.ru 307*1270Sigor@sysoev.ru if (!peer->closed) { 308*1270Sigor@sysoev.ru nxt_http_proto[peer->protocol].peer_read(task, peer); 309*1270Sigor@sysoev.ru } 310*1270Sigor@sysoev.ru } 311*1270Sigor@sysoev.ru 312*1270Sigor@sysoev.ru 313*1270Sigor@sysoev.ru void 314*1270Sigor@sysoev.ru nxt_http_proxy_buf_mem_free(nxt_task_t *task, nxt_http_request_t *r, 315*1270Sigor@sysoev.ru nxt_buf_t *b) 316*1270Sigor@sysoev.ru { 317*1270Sigor@sysoev.ru nxt_event_engine_buf_mem_free(task->thread->engine, b); 318*1270Sigor@sysoev.ru 319*1270Sigor@sysoev.ru nxt_mp_release(r->mem_pool); 320*1270Sigor@sysoev.ru } 321*1270Sigor@sysoev.ru 322*1270Sigor@sysoev.ru 323*1270Sigor@sysoev.ru static void 324*1270Sigor@sysoev.ru nxt_http_proxy_error(nxt_task_t *task, void *obj, void *data) 325*1270Sigor@sysoev.ru { 326*1270Sigor@sysoev.ru nxt_http_peer_t *peer; 327*1270Sigor@sysoev.ru nxt_http_request_t *r; 328*1270Sigor@sysoev.ru 329*1270Sigor@sysoev.ru r = obj; 330*1270Sigor@sysoev.ru peer = r->peer; 331*1270Sigor@sysoev.ru 332*1270Sigor@sysoev.ru nxt_http_proto[peer->protocol].peer_close(task, peer); 333*1270Sigor@sysoev.ru 334*1270Sigor@sysoev.ru nxt_mp_release(r->mem_pool); 335*1270Sigor@sysoev.ru 336*1270Sigor@sysoev.ru nxt_http_request_error(task, r, peer->status); 337*1270Sigor@sysoev.ru } 338*1270Sigor@sysoev.ru 339*1270Sigor@sysoev.ru 340*1270Sigor@sysoev.ru nxt_int_t 341*1270Sigor@sysoev.ru nxt_http_proxy_date(void *ctx, nxt_http_field_t *field, uintptr_t data) 342*1270Sigor@sysoev.ru { 343*1270Sigor@sysoev.ru nxt_http_request_t *r; 344*1270Sigor@sysoev.ru 345*1270Sigor@sysoev.ru r = ctx; 346*1270Sigor@sysoev.ru 347*1270Sigor@sysoev.ru r->resp.date = field; 348*1270Sigor@sysoev.ru 349*1270Sigor@sysoev.ru return NXT_OK; 350*1270Sigor@sysoev.ru } 351*1270Sigor@sysoev.ru 352*1270Sigor@sysoev.ru 353*1270Sigor@sysoev.ru nxt_int_t 354*1270Sigor@sysoev.ru nxt_http_proxy_content_length(void *ctx, nxt_http_field_t *field, 355*1270Sigor@sysoev.ru uintptr_t data) 356*1270Sigor@sysoev.ru { 357*1270Sigor@sysoev.ru nxt_off_t n; 358*1270Sigor@sysoev.ru nxt_http_request_t *r; 359*1270Sigor@sysoev.ru 360*1270Sigor@sysoev.ru r = ctx; 361*1270Sigor@sysoev.ru 362*1270Sigor@sysoev.ru r->resp.content_length = field; 363*1270Sigor@sysoev.ru 364*1270Sigor@sysoev.ru n = nxt_off_t_parse(field->value, field->value_length); 365*1270Sigor@sysoev.ru 366*1270Sigor@sysoev.ru if (nxt_fast_path(n >= 0)) { 367*1270Sigor@sysoev.ru r->resp.content_length_n = n; 368*1270Sigor@sysoev.ru } 369*1270Sigor@sysoev.ru 370*1270Sigor@sysoev.ru return NXT_OK; 371*1270Sigor@sysoev.ru } 372*1270Sigor@sysoev.ru 373*1270Sigor@sysoev.ru 374*1270Sigor@sysoev.ru nxt_int_t 375*1270Sigor@sysoev.ru nxt_http_proxy_skip(void *ctx, nxt_http_field_t *field, uintptr_t data) 376*1270Sigor@sysoev.ru { 377*1270Sigor@sysoev.ru field->skip = 1; 378*1270Sigor@sysoev.ru 379*1270Sigor@sysoev.ru return NXT_OK; 380*1270Sigor@sysoev.ru } 381