xref: /unit/go/response.go (revision 1323:6dfc9895e25e)
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	"net/http"
15)
16
17type response struct {
18	header     http.Header
19	headerSent bool
20	req        *http.Request
21	c_req      C.uintptr_t
22	ch         chan int
23}
24
25func new_response(c_req C.uintptr_t, req *http.Request) *response {
26	resp := &response{
27		header: http.Header{},
28		req:    req,
29		c_req:  c_req,
30	}
31
32	return resp
33}
34
35func (r *response) Header() http.Header {
36	return r.header
37}
38
39func (r *response) Write(p []byte) (n int, err error) {
40	if !r.headerSent {
41		r.WriteHeader(http.StatusOK)
42	}
43
44	l := len(p)
45	written := int(0)
46	br := buf_ref(p)
47
48	for written < l {
49		res := C.nxt_cgo_response_write(r.c_req, br, C.uint32_t(l - written))
50
51		written += int(res)
52		br += C.uintptr_t(res)
53
54		if (written < l) {
55			if r.ch == nil {
56				r.ch = make(chan int, 2)
57			}
58
59			wait_shm_ack(r.ch)
60		}
61	}
62
63	return written, nil
64}
65
66func (r *response) WriteHeader(code int) {
67	if r.headerSent {
68		// Note: explicitly using Stderr, as Stdout is our HTTP output.
69		nxt_go_warn("multiple response.WriteHeader calls")
70		return
71	}
72	r.headerSent = true
73
74	// Set a default Content-Type
75	if _, hasType := r.header["Content-Type"]; !hasType {
76		r.header.Add("Content-Type", "text/html; charset=utf-8")
77	}
78
79	fields := 0
80	fields_size := 0
81
82	for k, vv := range r.header {
83		for _, v := range vv {
84			fields++
85			fields_size += len(k) + len(v)
86		}
87	}
88
89	C.nxt_cgo_response_create(r.c_req, C.int(code), C.int(fields),
90		C.uint32_t(fields_size))
91
92	for k, vv := range r.header {
93		for _, v := range vv {
94			C.nxt_cgo_response_add_field(r.c_req, str_ref(k), C.uint8_t(len(k)),
95				str_ref(v), C.uint32_t(len(v)))
96		}
97	}
98
99	C.nxt_cgo_response_send(r.c_req)
100}
101
102func (r *response) Flush() {
103	if !r.headerSent {
104		r.WriteHeader(http.StatusOK)
105	}
106}
107
108var observer_registry_ observable
109
110func wait_shm_ack(c chan int) {
111	observer_registry_.attach(c)
112
113	_ = <-c
114}
115
116//export nxt_go_shm_ack_handler
117func nxt_go_shm_ack_handler() {
118	observer_registry_.notify(1)
119}
120