teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

動作例追記

2019/11/22 13:52

投稿

nobonobo
nobonobo

スコア3367

answer CHANGED
@@ -10,4 +10,111 @@
10
10
  HTTP1.1以降はConnectionヘッダを省略したリクエストはコネクションをキープしようとするという挙動です。
11
11
  [HTTP1.1の接続仕様(MDN)](https://developer.mozilla.org/ja/docs/Web/HTTP/Connection_management_in_HTTP_1.x)
12
12
 
13
- curlの「-H `Connection: close'」などを付け足して見てみるのも良いかもしれません。
13
+ curlの「-H `Connection: close'」などを付け足して見てみるのも良いかもしれません。
14
+
15
+ ## 追記
16
+
17
+ 動くようなコードに修正してみました。
18
+ net/textprotoのReaderの場合、必要以上に読むことはないのでこういう用途に適しています。
19
+
20
+ ```go
21
+ package main
22
+
23
+ import (
24
+ "bufio"
25
+ "fmt"
26
+ "io"
27
+ "log"
28
+ "net"
29
+ "net/textproto"
30
+ "strconv"
31
+ "strings"
32
+ )
33
+
34
+ func handleConn(conn net.Conn) {
35
+ defer conn.Close()
36
+ reader := bufio.NewReader(conn)
37
+ scanner := textproto.NewReader(reader)
38
+ i := 0
39
+ headers := map[string]string{}
40
+ var url, method string
41
+ for {
42
+ ln, err := scanner.ReadLine()
43
+ if err != nil {
44
+ log.Println(err)
45
+ return
46
+ }
47
+
48
+ if i == 0 {
49
+ fs := strings.Fields(ln)
50
+ method = fs[0]
51
+ url = fs[1]
52
+ fmt.Println("METHOD", method)
53
+ fmt.Println("URL", url)
54
+ } else {
55
+ // in headers now
56
+ // when line is empty, header is done
57
+ if ln == "" {
58
+ break
59
+ }
60
+ fs := strings.SplitN(ln, ": ", 2)
61
+ headers[fs[0]] = fs[1]
62
+ }
63
+
64
+ i++
65
+ }
66
+
67
+ // parse body
68
+
69
+ // ここがポイントと思われる
70
+ if method == "POST" || method == "PUT" {
71
+ amt, _ := strconv.Atoi(headers["Content-Length"])
72
+ buf := make([]byte, amt)
73
+ // 単に ReadFull ではデータを読み込むことができない
74
+ _, err := io.ReadFull(reader, buf)
75
+ if err != nil {
76
+ fmt.Println("error:", err)
77
+ }
78
+ // in buf we will have the POST content
79
+ fmt.Println("BODY:", string(buf))
80
+ }
81
+ // ここまで
82
+ // response
83
+ body := `
84
+ <!DOCTYPE html>
85
+ <html lang="en">
86
+ <head>
87
+ <meta charset="UTF-8">
88
+ <title></title>
89
+ </head>
90
+ <body>
91
+ <form method="POST">
92
+ <input type="text" name="key" value="">
93
+ <input type="submit">
94
+ </form>
95
+ </body>
96
+ </html>
97
+ `
98
+
99
+ io.WriteString(conn, "HTTP/1.1 200 OK\r\n")
100
+ fmt.Fprintf(conn, "Content-Length: %d\r\n", len(body))
101
+ io.WriteString(conn, "\r\n")
102
+ io.WriteString(conn, body)
103
+ }
104
+
105
+ func main() {
106
+ server, err := net.Listen("tcp", ":9000")
107
+ if err != nil {
108
+ log.Fatalln(err.Error())
109
+ }
110
+ defer server.Close()
111
+
112
+ for {
113
+ conn, err := server.Accept()
114
+ if err != nil {
115
+ log.Fatalln(err.Error())
116
+ }
117
+ go handleConn(conn)
118
+ }
119
+ }
120
+ ```

1

追記

2019/11/22 13:51

投稿

nobonobo
nobonobo

スコア3367

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