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