1/* 2 * Copyright (C) Max Romanov 3 * Copyright (C) NGINX, Inc. 4 */ 5 6package unit 7 8/* 9#include "nxt_cgo_lib.h" 10*/ 11import "C" 12 13import ( 14 "io" 15 "net/http" 16 "net/url" 17 "crypto/tls" 18 "unsafe" 19) 20 21type request struct { 22 req http.Request 23 resp response 24 c_req *C.nxt_unit_request_info_t 25} 26 27func (r *request) Read(p []byte) (n int, err error) { 28 res := C.nxt_cgo_request_read(r.c_req, buf_ref(p), C.uint32_t(len(p))) 29 30 if res == 0 && len(p) > 0 { 31 return 0, io.EOF 32 } 33 34 return int(res), nil 35} 36 37func (r *request) Close() error { 38 return nil 39} 40 41func new_request(c_req *C.nxt_unit_request_info_t) (r *request, err error) { 42 req := c_req.request 43 44 uri := GoStringN(&req.target, C.int(req.target_length)) 45 46 URL, err := url.ParseRequestURI(uri) 47 if err != nil { 48 return nil, err 49 } 50 51 proto := GoStringN(&req.version, C.int(req.version_length)) 52 53 r = &request{ 54 req: http.Request { 55 URL: URL, 56 Header: http.Header{}, 57 RequestURI: uri, 58 Method: GoStringN(&req.method, C.int(req.method_length)), 59 Proto: proto, 60 ProtoMajor: 1, 61 ProtoMinor: int(proto[7] - '0'), 62 ContentLength: int64(req.content_length), 63 Host: GoStringN(&req.server_name, C.int(req.server_name_length)), 64 RemoteAddr: GoStringN(&req.remote, C.int(req.remote_length)), 65 }, 66 resp: response{header: http.Header{}, c_req: c_req}, 67 c_req: c_req, 68 } 69 70 r.req.Body = r 71 72 if req.tls != 0 { 73 r.req.TLS = &tls.ConnectionState{ } 74 r.req.URL.Scheme = "https" 75 76 } else { 77 r.req.URL.Scheme = "http" 78 } 79 80 fields := get_fields(req) 81 82 for i := 0; i < len(fields); i++ { 83 f := &fields[i] 84 85 n := GoStringN(&f.name, C.int(f.name_length)) 86 v := GoStringN(&f.value, C.int(f.value_length)) 87 88 r.req.Header.Add(n, v) 89 } 90 91 return r, nil 92} 93 94func get_fields(req *C.nxt_unit_request_t) []C.nxt_unit_field_t { 95 f := uintptr(unsafe.Pointer(req)) + uintptr(C.NXT_FIELDS_OFFSET) 96 97 h := &slice_header{ 98 Data: unsafe.Pointer(f), 99 Len: int(req.fields_count), 100 Cap: int(req.fields_count), 101 } 102 103 return *(*[]C.nxt_unit_field_t)(unsafe.Pointer(h)) 104} 105 106//export nxt_go_request_handler 107func nxt_go_request_handler(c_req *C.nxt_unit_request_info_t) { 108 109 go func(c_req *C.nxt_unit_request_info_t, handler http.Handler) { 110 111 ctx := c_req.ctx 112 113 for { 114 r, err := new_request(c_req) 115 116 if err == nil { 117 handler.ServeHTTP(&r.resp, &r.req) 118 119 if !r.resp.header_sent { 120 r.resp.WriteHeader(http.StatusOK) 121 } 122 123 C.nxt_unit_request_done(c_req, C.NXT_UNIT_OK) 124 125 } else { 126 C.nxt_unit_request_done(c_req, C.NXT_UNIT_ERROR) 127 } 128 129 c_req = C.nxt_unit_dequeue_request(ctx) 130 if c_req == nil { 131 break 132 } 133 } 134 135 }(c_req, get_handler(uintptr(c_req.unit.data))) 136} 137