xref: /unit/go/response.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	"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}
23
24func new_response(c_req C.uintptr_t, req *http.Request) *response {
25	resp := &response{
26		header: http.Header{},
27		req:    req,
28		c_req:  c_req,
29	}
30
31	return resp
32}
33
34func (r *response) Header() http.Header {
35	return r.header
36}
37
38func (r *response) Write(p []byte) (n int, err error) {
39	if !r.headerSent {
40		r.WriteHeader(http.StatusOK)
41	}
42
43	res := C.nxt_cgo_response_write(r.c_req, buf_ref(p), C.uint32_t(len(p)))
44	return int(res), nil
45}
46
47func (r *response) WriteHeader(code int) {
48	if r.headerSent {
49		// Note: explicitly using Stderr, as Stdout is our HTTP output.
50		nxt_go_warn("multiple response.WriteHeader calls")
51		return
52	}
53	r.headerSent = true
54
55	// Set a default Content-Type
56	if _, hasType := r.header["Content-Type"]; !hasType {
57		r.header.Add("Content-Type", "text/html; charset=utf-8")
58	}
59
60	fields := 0
61	fields_size := 0
62
63	for k, vv := range r.header {
64		for _, v := range vv {
65			fields++
66			fields_size += len(k) + len(v)
67		}
68	}
69
70	C.nxt_cgo_response_create(r.c_req, C.int(code), C.int(fields),
71		C.uint32_t(fields_size))
72
73	for k, vv := range r.header {
74		for _, v := range vv {
75			C.nxt_cgo_response_add_field(r.c_req, str_ref(k), C.uint8_t(len(k)),
76				str_ref(v), C.uint32_t(len(v)))
77		}
78	}
79
80	C.nxt_cgo_response_send(r.c_req)
81}
82
83func (r *response) Flush() {
84	if !r.headerSent {
85		r.WriteHeader(http.StatusOK)
86	}
87}
88