回答編集履歴

2

動作例追記

2019/11/22 13:52

投稿

nobonobo
nobonobo

スコア3367

test CHANGED
@@ -23,3 +23,217 @@
23
23
 
24
24
 
25
25
  curlの「-H `Connection: close'」などを付け足して見てみるのも良いかもしれません。
26
+
27
+
28
+
29
+ ## 追記
30
+
31
+
32
+
33
+ 動くようなコードに修正してみました。
34
+
35
+ net/textprotoのReaderの場合、必要以上に読むことはないのでこういう用途に適しています。
36
+
37
+
38
+
39
+ ```go
40
+
41
+ package main
42
+
43
+
44
+
45
+ import (
46
+
47
+ "bufio"
48
+
49
+ "fmt"
50
+
51
+ "io"
52
+
53
+ "log"
54
+
55
+ "net"
56
+
57
+ "net/textproto"
58
+
59
+ "strconv"
60
+
61
+ "strings"
62
+
63
+ )
64
+
65
+
66
+
67
+ func handleConn(conn net.Conn) {
68
+
69
+ defer conn.Close()
70
+
71
+ reader := bufio.NewReader(conn)
72
+
73
+ scanner := textproto.NewReader(reader)
74
+
75
+ i := 0
76
+
77
+ headers := map[string]string{}
78
+
79
+ var url, method string
80
+
81
+ for {
82
+
83
+ ln, err := scanner.ReadLine()
84
+
85
+ if err != nil {
86
+
87
+ log.Println(err)
88
+
89
+ return
90
+
91
+ }
92
+
93
+
94
+
95
+ if i == 0 {
96
+
97
+ fs := strings.Fields(ln)
98
+
99
+ method = fs[0]
100
+
101
+ url = fs[1]
102
+
103
+ fmt.Println("METHOD", method)
104
+
105
+ fmt.Println("URL", url)
106
+
107
+ } else {
108
+
109
+ // in headers now
110
+
111
+ // when line is empty, header is done
112
+
113
+ if ln == "" {
114
+
115
+ break
116
+
117
+ }
118
+
119
+ fs := strings.SplitN(ln, ": ", 2)
120
+
121
+ headers[fs[0]] = fs[1]
122
+
123
+ }
124
+
125
+
126
+
127
+ i++
128
+
129
+ }
130
+
131
+
132
+
133
+ // parse body
134
+
135
+
136
+
137
+ // ここがポイントと思われる
138
+
139
+ if method == "POST" || method == "PUT" {
140
+
141
+ amt, _ := strconv.Atoi(headers["Content-Length"])
142
+
143
+ buf := make([]byte, amt)
144
+
145
+ // 単に ReadFull ではデータを読み込むことができない
146
+
147
+ _, err := io.ReadFull(reader, buf)
148
+
149
+ if err != nil {
150
+
151
+ fmt.Println("error:", err)
152
+
153
+ }
154
+
155
+ // in buf we will have the POST content
156
+
157
+ fmt.Println("BODY:", string(buf))
158
+
159
+ }
160
+
161
+ // ここまで
162
+
163
+ // response
164
+
165
+ body := `
166
+
167
+ <!DOCTYPE html>
168
+
169
+ <html lang="en">
170
+
171
+ <head>
172
+
173
+ <meta charset="UTF-8">
174
+
175
+ <title></title>
176
+
177
+ </head>
178
+
179
+ <body>
180
+
181
+ <form method="POST">
182
+
183
+ <input type="text" name="key" value="">
184
+
185
+ <input type="submit">
186
+
187
+ </form>
188
+
189
+ </body>
190
+
191
+ </html>
192
+
193
+ `
194
+
195
+
196
+
197
+ io.WriteString(conn, "HTTP/1.1 200 OK\r\n")
198
+
199
+ fmt.Fprintf(conn, "Content-Length: %d\r\n", len(body))
200
+
201
+ io.WriteString(conn, "\r\n")
202
+
203
+ io.WriteString(conn, body)
204
+
205
+ }
206
+
207
+
208
+
209
+ func main() {
210
+
211
+ server, err := net.Listen("tcp", ":9000")
212
+
213
+ if err != nil {
214
+
215
+ log.Fatalln(err.Error())
216
+
217
+ }
218
+
219
+ defer server.Close()
220
+
221
+
222
+
223
+ for {
224
+
225
+ conn, err := server.Accept()
226
+
227
+ if err != nil {
228
+
229
+ log.Fatalln(err.Error())
230
+
231
+ }
232
+
233
+ go handleConn(conn)
234
+
235
+ }
236
+
237
+ }
238
+
239
+ ```

1

追記

2019/11/22 13:51

投稿

nobonobo
nobonobo

スコア3367

test CHANGED
@@ -1,3 +1,7 @@
1
+ なぜ標準ライブラリを使わずに書いているのかは学習目的と仮定します。
2
+
3
+
4
+
1
5
  まずは、「io.ReadFull」の戻り値のerror値の内容を確認するように修正してください。もしnilではないのであればその内容を追記してください。
2
6
 
3
7
  「io.ReadFull」の次の行が実行されない可能性もあります。
@@ -7,3 +11,15 @@
7
11
  io.ReadFullの次に処理が進むのかを確認し、
8
12
 
9
13
  戻り値のerrorをログに出すなりしてその内容を教えて下さい。
14
+
15
+
16
+
17
+ 「io.ReadFull」の次の行が実行されない可能性の原因として考えられるのは
18
+
19
+ HTTP1.1以降はConnectionヘッダを省略したリクエストはコネクションをキープしようとするという挙動です。
20
+
21
+ [HTTP1.1の接続仕様(MDN)](https://developer.mozilla.org/ja/docs/Web/HTTP/Connection_management_in_HTTP_1.x)
22
+
23
+
24
+
25
+ curlの「-H `Connection: close'」などを付け足して見てみるのも良いかもしれません。