136 lines
2.6 KiB
Go
136 lines
2.6 KiB
Go
/*
|
|
* Copyright (C) Max Romanov
|
|
* Copyright (C) NGINX, Inc.
|
|
*/
|
|
|
|
package unit
|
|
|
|
/*
|
|
#include "nxt_cgo_lib.h"
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"crypto/tls"
|
|
"unsafe"
|
|
)
|
|
|
|
type request struct {
|
|
req http.Request
|
|
resp response
|
|
c_req *C.nxt_unit_request_info_t
|
|
}
|
|
|
|
func (r *request) Read(p []byte) (n int, err error) {
|
|
res := C.nxt_cgo_request_read(r.c_req, buf_ref(p), C.uint32_t(len(p)))
|
|
|
|
if res == 0 && len(p) > 0 {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
return int(res), nil
|
|
}
|
|
|
|
func (r *request) Close() error {
|
|
return nil
|
|
}
|
|
|
|
func new_request(c_req *C.nxt_unit_request_info_t) (r *request, err error) {
|
|
req := c_req.request
|
|
|
|
uri := GoStringN(&req.target, C.int(req.target_length))
|
|
|
|
URL, err := url.ParseRequestURI(uri)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
proto := GoStringN(&req.version, C.int(req.version_length))
|
|
|
|
r = &request{
|
|
req: http.Request {
|
|
URL: URL,
|
|
Header: http.Header{},
|
|
RequestURI: uri,
|
|
Method: GoStringN(&req.method, C.int(req.method_length)),
|
|
Proto: proto,
|
|
ProtoMajor: 1,
|
|
ProtoMinor: int(proto[7] - '0'),
|
|
ContentLength: int64(req.content_length),
|
|
Host: GoStringN(&req.server_name, C.int(req.server_name_length)),
|
|
RemoteAddr: GoStringN(&req.remote, C.int(req.remote_length)),
|
|
},
|
|
resp: response{header: http.Header{}, c_req: c_req},
|
|
c_req: c_req,
|
|
}
|
|
|
|
r.req.Body = r
|
|
|
|
if req.tls != 0 {
|
|
r.req.TLS = &tls.ConnectionState{ }
|
|
r.req.URL.Scheme = "https"
|
|
|
|
} else {
|
|
r.req.URL.Scheme = "http"
|
|
}
|
|
|
|
fields := get_fields(req)
|
|
|
|
for i := 0; i < len(fields); i++ {
|
|
f := &fields[i]
|
|
|
|
n := GoStringN(&f.name, C.int(f.name_length))
|
|
v := GoStringN(&f.value, C.int(f.value_length))
|
|
|
|
r.req.Header.Add(n, v)
|
|
}
|
|
|
|
return r, nil
|
|
}
|
|
|
|
func get_fields(req *C.nxt_unit_request_t) []C.nxt_unit_field_t {
|
|
f := uintptr(unsafe.Pointer(req)) + uintptr(C.NXT_FIELDS_OFFSET)
|
|
|
|
h := &slice_header{
|
|
Data: unsafe.Pointer(f),
|
|
Len: int(req.fields_count),
|
|
Cap: int(req.fields_count),
|
|
}
|
|
|
|
return *(*[]C.nxt_unit_field_t)(unsafe.Pointer(h))
|
|
}
|
|
|
|
//export nxt_go_request_handler
|
|
func nxt_go_request_handler(c_req *C.nxt_unit_request_info_t) {
|
|
|
|
go func(c_req *C.nxt_unit_request_info_t, handler http.Handler) {
|
|
|
|
ctx := c_req.ctx
|
|
|
|
for {
|
|
r, err := new_request(c_req)
|
|
|
|
if err == nil {
|
|
handler.ServeHTTP(&r.resp, &r.req)
|
|
|
|
if !r.resp.header_sent {
|
|
r.resp.WriteHeader(http.StatusOK)
|
|
}
|
|
|
|
C.nxt_unit_request_done(c_req, C.NXT_UNIT_OK)
|
|
|
|
} else {
|
|
C.nxt_unit_request_done(c_req, C.NXT_UNIT_ERROR)
|
|
}
|
|
|
|
c_req = C.nxt_unit_dequeue_request(ctx)
|
|
if c_req == nil {
|
|
break
|
|
}
|
|
}
|
|
|
|
}(c_req, get_handler(uintptr(c_req.unit.data)))
|
|
}
|