annotate fcgi/fcgi.go @ 11:350589d762a0 default tip

add cgi, remove tls, update docs
author Atarwn Gard <a@qwa.su>
date Thu, 19 Mar 2026 20:00:49 +0500
parents eb705d4cdcd7
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
1 // Copyright 2012 Junqing Tan <ivan@mysqlab.net> and The Go Authors
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
2 // Use of this source code is governed by a BSD-style
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
3 // Part of source code is from Go fcgi package
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
4
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
5 package fcgi
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
6
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
7 import (
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
8 "bufio"
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
9 "bytes"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
10 "encoding/binary"
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
11 "errors"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
12 "fmt"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
13 "io"
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
14 "io/ioutil"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
15 "mime/multipart"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
16 "net"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
17 "net/http"
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
18 "net/http/httputil"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
19 "net/textproto"
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
20 "net/url"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
21 "os"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
22 "path/filepath"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
23 "strconv"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
24 "strings"
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
25 "sync"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
26 "time"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
27 )
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
28
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
29 const FCGI_LISTENSOCK_FILENO uint8 = 0
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
30 const FCGI_HEADER_LEN uint8 = 8
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
31 const VERSION_1 uint8 = 1
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
32 const FCGI_NULL_REQUEST_ID uint8 = 0
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
33 const FCGI_KEEP_CONN uint8 = 1
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
34 const doubleCRLF = "\r\n\r\n"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
35
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
36 const (
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
37 FCGI_BEGIN_REQUEST uint8 = iota + 1
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
38 FCGI_ABORT_REQUEST
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
39 FCGI_END_REQUEST
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
40 FCGI_PARAMS
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
41 FCGI_STDIN
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
42 FCGI_STDOUT
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
43 FCGI_STDERR
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
44 FCGI_DATA
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
45 FCGI_GET_VALUES
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
46 FCGI_GET_VALUES_RESULT
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
47 FCGI_UNKNOWN_TYPE
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
48 FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
49 )
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
50
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
51 const (
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
52 FCGI_RESPONDER uint8 = iota + 1
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
53 FCGI_AUTHORIZER
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
54 FCGI_FILTER
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
55 )
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
56
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
57 const (
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
58 FCGI_REQUEST_COMPLETE uint8 = iota
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
59 FCGI_CANT_MPX_CONN
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
60 FCGI_OVERLOADED
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
61 FCGI_UNKNOWN_ROLE
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
62 )
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
63
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
64 const (
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
65 FCGI_MAX_CONNS string = "MAX_CONNS"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
66 FCGI_MAX_REQS string = "MAX_REQS"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
67 FCGI_MPXS_CONNS string = "MPXS_CONNS"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
68 )
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
69
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
70 const (
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
71 maxWrite = 65500 // 65530 may work, but for compatibility
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
72 maxPad = 255
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
73 )
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
74
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
75 type header struct {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
76 Version uint8
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
77 Type uint8
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
78 Id uint16
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
79 ContentLength uint16
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
80 PaddingLength uint8
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
81 Reserved uint8
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
82 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
83
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
84 // for padding so we don't have to allocate all the time
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
85 // not synchronized because we don't care what the contents are
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
86 var pad [maxPad]byte
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
87
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
88 func (h *header) init(recType uint8, reqId uint16, contentLength int) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
89 h.Version = 1
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
90 h.Type = recType
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
91 h.Id = reqId
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
92 h.ContentLength = uint16(contentLength)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
93 h.PaddingLength = uint8(-contentLength & 7)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
94 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
95
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
96 type record struct {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
97 h header
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
98 rbuf []byte
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
99 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
100
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
101 func (rec *record) read(r io.Reader) (buf []byte, err error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
102 if err = binary.Read(r, binary.BigEndian, &rec.h); err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
103 return
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
104 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
105 if rec.h.Version != 1 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
106 err = errors.New("fcgi: invalid header version")
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
107 return
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
108 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
109 if rec.h.Type == FCGI_END_REQUEST {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
110 err = io.EOF
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
111 return
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
112 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
113 n := int(rec.h.ContentLength) + int(rec.h.PaddingLength)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
114 if len(rec.rbuf) < n {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
115 rec.rbuf = make([]byte, n)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
116 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
117 if n, err = io.ReadFull(r, rec.rbuf[:n]); err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
118 return
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
119 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
120 buf = rec.rbuf[:int(rec.h.ContentLength)]
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
121
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
122 return
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
123 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
124
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
125 type FCGIClient struct {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
126 mutex sync.Mutex
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
127 rwc io.ReadWriteCloser
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
128 h header
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
129 buf bytes.Buffer
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
130 keepAlive bool
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
131 reqId uint16
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
132 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
133
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
134 // Connects to the fcgi responder at the specified network address.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
135 // See func net.Dial for a description of the network and address parameters.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
136 func Dial(network, address string) (fcgi *FCGIClient, err error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
137 var conn net.Conn
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
138
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
139 conn, err = net.Dial(network, address)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
140 if err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
141 return
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
142 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
143
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
144 fcgi = &FCGIClient{
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
145 rwc: conn,
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
146 keepAlive: false,
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
147 reqId: 1,
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
148 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
149
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
150 return
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
151 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
152
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
153 // Connects to the fcgi responder at the specified network address with timeout
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
154 // See func net.DialTimeout for a description of the network, address and timeout parameters.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
155 func DialTimeout(network, address string, timeout time.Duration) (fcgi *FCGIClient, err error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
156
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
157 var conn net.Conn
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
158
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
159 conn, err = net.DialTimeout(network, address, timeout)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
160 if err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
161 return
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
162 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
163
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
164 fcgi = &FCGIClient{
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
165 rwc: conn,
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
166 keepAlive: false,
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
167 reqId: 1,
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
168 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
169
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
170 return
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
171 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
172
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
173 // Close fcgi connnection
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
174 func (this *FCGIClient) Close() {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
175 this.rwc.Close()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
176 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
177
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
178 func (this *FCGIClient) writeRecord(recType uint8, content []byte) (err error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
179 this.mutex.Lock()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
180 defer this.mutex.Unlock()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
181 this.buf.Reset()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
182 this.h.init(recType, this.reqId, len(content))
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
183 if err := binary.Write(&this.buf, binary.BigEndian, this.h); err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
184 return err
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
185 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
186 if _, err := this.buf.Write(content); err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
187 return err
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
188 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
189 if _, err := this.buf.Write(pad[:this.h.PaddingLength]); err != nil {
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
190 return err
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
191 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
192 _, err = this.rwc.Write(this.buf.Bytes())
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
193 return err
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
194 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
195
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
196 func (this *FCGIClient) writeBeginRequest(role uint16, flags uint8) error {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
197 b := [8]byte{byte(role >> 8), byte(role), flags}
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
198 return this.writeRecord(FCGI_BEGIN_REQUEST, b[:])
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
199 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
200
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
201 func (this *FCGIClient) writeEndRequest(appStatus int, protocolStatus uint8) error {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
202 b := make([]byte, 8)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
203 binary.BigEndian.PutUint32(b, uint32(appStatus))
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
204 b[4] = protocolStatus
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
205 return this.writeRecord(FCGI_END_REQUEST, b)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
206 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
207
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
208 func (this *FCGIClient) writePairs(recType uint8, pairs map[string]string) error {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
209 w := newWriter(this, recType)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
210 b := make([]byte, 8)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
211 nn := 0
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
212 for k, v := range pairs {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
213 m := 8 + len(k) + len(v)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
214 if m > maxWrite {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
215 // param data size exceed 65535 bytes"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
216 vl := maxWrite - 8 - len(k)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
217 v = v[:vl]
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
218 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
219 n := encodeSize(b, uint32(len(k)))
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
220 n += encodeSize(b[n:], uint32(len(v)))
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
221 m = n + len(k) + len(v)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
222 if (nn + m) > maxWrite {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
223 w.Flush()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
224 nn = 0
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
225 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
226 nn += m
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
227 if _, err := w.Write(b[:n]); err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
228 return err
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
229 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
230 if _, err := w.WriteString(k); err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
231 return err
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
232 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
233 if _, err := w.WriteString(v); err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
234 return err
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
235 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
236 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
237 w.Close()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
238 return nil
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
239 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
240
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
241 func readSize(s []byte) (uint32, int) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
242 if len(s) == 0 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
243 return 0, 0
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
244 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
245 size, n := uint32(s[0]), 1
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
246 if size&(1<<7) != 0 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
247 if len(s) < 4 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
248 return 0, 0
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
249 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
250 n = 4
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
251 size = binary.BigEndian.Uint32(s)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
252 size &^= 1 << 31
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
253 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
254 return size, n
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
255 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
256
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
257 func readString(s []byte, size uint32) string {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
258 if size > uint32(len(s)) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
259 return ""
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
260 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
261 return string(s[:size])
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
262 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
263
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
264 func encodeSize(b []byte, size uint32) int {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
265 if size > 127 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
266 size |= 1 << 31
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
267 binary.BigEndian.PutUint32(b, size)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
268 return 4
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
269 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
270 b[0] = byte(size)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
271 return 1
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
272 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
273
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
274 // bufWriter encapsulates bufio.Writer but also closes the underlying stream when
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
275 // Closed.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
276 type bufWriter struct {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
277 closer io.Closer
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
278 *bufio.Writer
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
279 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
280
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
281 func (w *bufWriter) Close() error {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
282 if err := w.Writer.Flush(); err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
283 w.closer.Close()
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
284 return err
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
285 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
286 return w.closer.Close()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
287 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
288
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
289 func newWriter(c *FCGIClient, recType uint8) *bufWriter {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
290 s := &streamWriter{c: c, recType: recType}
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
291 w := bufio.NewWriterSize(s, maxWrite)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
292 return &bufWriter{s, w}
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
293 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
294
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
295 // streamWriter abstracts out the separation of a stream into discrete records.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
296 // It only writes maxWrite bytes at a time.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
297 type streamWriter struct {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
298 c *FCGIClient
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
299 recType uint8
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
300 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
301
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
302 func (w *streamWriter) Write(p []byte) (int, error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
303 nn := 0
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
304 for len(p) > 0 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
305 n := len(p)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
306 if n > maxWrite {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
307 n = maxWrite
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
308 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
309 if err := w.c.writeRecord(w.recType, p[:n]); err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
310 return nn, err
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
311 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
312 nn += n
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
313 p = p[n:]
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
314 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
315 return nn, nil
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
316 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
317
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
318 func (w *streamWriter) Close() error {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
319 // send empty record to close the stream
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
320 return w.c.writeRecord(w.recType, nil)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
321 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
322
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
323 type streamReader struct {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
324 c *FCGIClient
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
325 buf []byte
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
326 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
327
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
328 func (w *streamReader) Read(p []byte) (n int, err error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
329
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
330 if len(p) > 0 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
331 if len(w.buf) == 0 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
332 rec := &record{}
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
333 w.buf, err = rec.read(w.c.rwc)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
334 if err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
335 return
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
336 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
337 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
338
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
339 n = len(p)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
340 if n > len(w.buf) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
341 n = len(w.buf)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
342 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
343 copy(p, w.buf[:n])
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
344 w.buf = w.buf[n:]
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
345 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
346
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
347 return
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
348 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
349
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
350 // Do made the request and returns a io.Reader that translates the data read
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
351 // from fcgi responder out of fcgi packet before returning it.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
352 func (this *FCGIClient) Do(p map[string]string, req io.Reader) (r io.Reader, err error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
353 err = this.writeBeginRequest(uint16(FCGI_RESPONDER), 0)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
354 if err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
355 return
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
356 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
357
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
358 err = this.writePairs(FCGI_PARAMS, p)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
359 if err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
360 return
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
361 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
362
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
363 body := newWriter(this, FCGI_STDIN)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
364 if req != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
365 io.Copy(body, req)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
366 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
367 body.Close()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
368
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
369 r = &streamReader{c: this}
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
370 return
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
371 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
372
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
373 type badStringError struct {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
374 what string
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
375 str string
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
376 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
377
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
378 func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
379
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
380 // Request returns a HTTP Response with Header and Body
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
381 // from fcgi responder
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
382 func (this *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http.Response, err error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
383
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
384 r, err := this.Do(p, req)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
385 if err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
386 return
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
387 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
388
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
389 rb := bufio.NewReader(r)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
390 tp := textproto.NewReader(rb)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
391 resp = new(http.Response)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
392 // Parse the first line of the response.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
393 line, err := tp.ReadLine()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
394 if err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
395 if err == io.EOF {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
396 err = io.ErrUnexpectedEOF
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
397 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
398 return nil, err
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
399 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
400 if i := strings.IndexByte(line, ' '); i == -1 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
401 err = &badStringError{"malformed HTTP response", line}
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
402 } else {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
403 resp.Proto = line[:i]
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
404 resp.Status = strings.TrimLeft(line[i+1:], " ")
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
405 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
406 statusCode := resp.Status
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
407 if i := strings.IndexByte(resp.Status, ' '); i != -1 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
408 statusCode = resp.Status[:i]
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
409 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
410 if len(statusCode) != 3 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
411 err = &badStringError{"malformed HTTP status code", statusCode}
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
412 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
413 resp.StatusCode, err = strconv.Atoi(statusCode)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
414 if err != nil || resp.StatusCode < 0 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
415 err = &badStringError{"malformed HTTP status code", statusCode}
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
416 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
417 var ok bool
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
418 if resp.ProtoMajor, resp.ProtoMinor, ok = http.ParseHTTPVersion(resp.Proto); !ok {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
419 err = &badStringError{"malformed HTTP version", resp.Proto}
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
420 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
421 // Parse the response headers.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
422 mimeHeader, err := tp.ReadMIMEHeader()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
423 if err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
424 if err == io.EOF {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
425 err = io.ErrUnexpectedEOF
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
426 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
427 return nil, err
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
428 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
429 resp.Header = http.Header(mimeHeader)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
430 // TODO: fixTransferEncoding ?
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
431 resp.TransferEncoding = resp.Header["Transfer-Encoding"]
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
432 resp.ContentLength, _ = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
433
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
434 if chunked(resp.TransferEncoding) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
435 resp.Body = ioutil.NopCloser(httputil.NewChunkedReader(rb))
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
436 } else {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
437 resp.Body = ioutil.NopCloser(rb)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
438 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
439 return
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
440 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
441
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
442 // Get issues a GET request to the fcgi responder.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
443 func (this *FCGIClient) Get(p map[string]string) (resp *http.Response, err error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
444
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
445 p["REQUEST_METHOD"] = "GET"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
446 p["CONTENT_LENGTH"] = "0"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
447
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
448 return this.Request(p, nil)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
449 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
450
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
451 // Get issues a Post request to the fcgi responder. with request body
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
452 // in the format that bodyType specified
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
453 func (this *FCGIClient) Post(p map[string]string, bodyType string, body io.Reader, l int) (resp *http.Response, err error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
454
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
455 if len(p["REQUEST_METHOD"]) == 0 || p["REQUEST_METHOD"] == "GET" {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
456 p["REQUEST_METHOD"] = "POST"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
457 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
458 p["CONTENT_LENGTH"] = strconv.Itoa(l)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
459 if len(bodyType) > 0 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
460 p["CONTENT_TYPE"] = bodyType
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
461 } else {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
462 p["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
463 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
464
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
465 return this.Request(p, body)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
466 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
467
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
468 // PostForm issues a POST to the fcgi responder, with form
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
469 // as a string key to a list values (url.Values)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
470 func (this *FCGIClient) PostForm(p map[string]string, data url.Values) (resp *http.Response, err error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
471 body := bytes.NewReader([]byte(data.Encode()))
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
472 return this.Post(p, "application/x-www-form-urlencoded", body, body.Len())
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
473 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
474
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
475 // PostFile issues a POST to the fcgi responder in multipart(RFC 2046) standard,
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
476 // with form as a string key to a list values (url.Values),
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
477 // and/or with file as a string key to a list file path.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
478 func (this *FCGIClient) PostFile(p map[string]string, data url.Values, file map[string]string) (resp *http.Response, err error) {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
479 buf := &bytes.Buffer{}
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
480 writer := multipart.NewWriter(buf)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
481 bodyType := writer.FormDataContentType()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
482
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
483 for key, val := range data {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
484 for _, v0 := range val {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
485 err = writer.WriteField(key, v0)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
486 if err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
487 return
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
488 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
489 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
490 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
491
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
492 for key, val := range file {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
493 fd, e := os.Open(val)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
494 if e != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
495 return nil, e
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
496 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
497 defer fd.Close()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
498
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
499 part, e := writer.CreateFormFile(key, filepath.Base(val))
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
500 if e != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
501 return nil, e
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
502 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
503 _, err = io.Copy(part, fd)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
504 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
505
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
506 err = writer.Close()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
507 if err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
508 return
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
509 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
510
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
511 return this.Post(p, bodyType, buf, buf.Len())
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
512 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
513
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
514 // Checks whether chunked is part of the encodings stack
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
515 func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }