xref: /unit/go/request.go (revision 1316:5b767c6bfd0a)
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.uintptr_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	C.nxt_cgo_request_close(r.c_req)
39	return nil
40}
41
42func (r *request) response() *response {
43	if r.resp == nil {
44		r.resp = new_response(r.c_req, &r.req)
45	}
46
47	return r.resp
48}
49
50func (r *request) done() {
51	resp := r.response()
52	if !resp.headerSent {
53		resp.WriteHeader(http.StatusOK)
54	}
55	C.nxt_cgo_request_done(r.c_req, 0)
56}
57
58func get_request(go_req uintptr) *request {
59	return (*request)(unsafe.Pointer(go_req))
60}
61
62//export nxt_go_request_create
63func nxt_go_request_create(c_req C.uintptr_t,
64	c_method *C.nxt_cgo_str_t, c_uri *C.nxt_cgo_str_t) uintptr {
65
66	uri := C.GoStringN(c_uri.start, c_uri.length)
67
68	var URL *url.URL
69	var err error
70	if URL, err = url.ParseRequestURI(uri); err != nil {
71		return 0
72	}
73
74	r := &request{
75		req: http.Request{
76			Method:     C.GoStringN(c_method.start, c_method.length),
77			URL:        URL,
78			Header:     http.Header{},
79			Body:       nil,
80			RequestURI: uri,
81		},
82		c_req: c_req,
83	}
84	r.req.Body = r
85
86	return uintptr(unsafe.Pointer(r))
87}
88
89//export nxt_go_request_set_proto
90func nxt_go_request_set_proto(go_req uintptr, proto *C.nxt_cgo_str_t,
91	maj C.int, min C.int) {
92
93	r := get_request(go_req)
94	r.req.Proto = C.GoStringN(proto.start, proto.length)
95	r.req.ProtoMajor = int(maj)
96	r.req.ProtoMinor = int(min)
97}
98
99//export nxt_go_request_add_header
100func nxt_go_request_add_header(go_req uintptr, name *C.nxt_cgo_str_t,
101	value *C.nxt_cgo_str_t) {
102
103	r := get_request(go_req)
104	r.req.Header.Add(C.GoStringN(name.start, name.length),
105		C.GoStringN(value.start, value.length))
106}
107
108//export nxt_go_request_set_content_length
109func nxt_go_request_set_content_length(go_req uintptr, l C.int64_t) {
110	get_request(go_req).req.ContentLength = int64(l)
111}
112
113//export nxt_go_request_set_host
114func nxt_go_request_set_host(go_req uintptr, host *C.nxt_cgo_str_t) {
115	get_request(go_req).req.Host = C.GoStringN(host.start, host.length)
116}
117
118//export nxt_go_request_set_url
119func nxt_go_request_set_url(go_req uintptr, scheme *C.char) {
120	get_request(go_req).req.URL.Scheme = C.GoString(scheme)
121}
122
123//export nxt_go_request_set_remote_addr
124func nxt_go_request_set_remote_addr(go_req uintptr, addr *C.nxt_cgo_str_t) {
125
126	get_request(go_req).req.RemoteAddr = C.GoStringN(addr.start, addr.length)
127}
128
129//export nxt_go_request_set_tls
130func nxt_go_request_set_tls(go_req uintptr) {
131
132	get_request(go_req).req.TLS = &tls.ConnectionState{ }
133}
134
135//export nxt_go_request_handler
136func nxt_go_request_handler(go_req uintptr, h uintptr) {
137	r := get_request(go_req)
138	handler := get_handler(h)
139
140	go func(r *request) {
141		handler.ServeHTTP(r.response(), &r.req)
142		r.done()
143	}(r)
144}
145