Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit bde1691

Browse files
committed
Update http code
1 parent d7db230 commit bde1691

File tree

4 files changed

+161
-0
lines changed

4 files changed

+161
-0
lines changed

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.test
2+
*.cpu
3+
*.svg

‎http/test_http_v1/README.md‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
## Fix the race
2+
3+
If your code has data races, all bets are off and you're just waiting for a crash. The runtime promises nothing if you have a data race.
4+
5+
Multiple options:
6+
7+
- use channels
8+
- use a Mutex
9+
- use atomic
10+
11+
### Mutex
12+
13+
```go
14+
var visitors struct {
15+
sync.Mutex
16+
n int
17+
}
18+
...
19+
func foo() {
20+
...
21+
visitors.Lock()
22+
visitors.n++
23+
yourVisitorNumber := visitors.n
24+
visitors.Unlock()
25+
```
26+
[used here](./demo_test.go#L11-L14)
27+
28+
### Atomic
29+
30+
```go
31+
var visitors int64 // must be accessed atomically
32+
...
33+
func foo() {
34+
...
35+
visitNum := atomic.AddInt64(&visitors, 1)
36+
```

‎http/test_http_v1/demo.go‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"net/http"
7+
"regexp"
8+
"sync"
9+
)
10+
11+
var visitors struct {
12+
sync.Mutex
13+
n int
14+
}
15+
16+
func handleHi(w http.ResponseWriter, r *http.Request) {
17+
if match, _ := regexp.MatchString(`^\w*$`, r.FormValue("color")); !match {
18+
http.Error(w, "Optional color is invalid", http.StatusBadRequest)
19+
return
20+
}
21+
visitors.Lock()
22+
visitors.n++
23+
yourVisitorNumber := visitors.n
24+
visitors.Unlock()
25+
w.Header().Set("Content-Type", "text/html; charset=utf-8")
26+
w.Write([]byte("<h1 style='color: " + r.FormValue("color") +
27+
"'>Welcome!</h1>You are visitor number " + fmt.Sprint(yourVisitorNumber) + "!"))
28+
}
29+
30+
func main() {
31+
log.Printf("Starting on port 8080")
32+
http.HandleFunc("/hi", handleHi)
33+
log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
34+
}

‎http/test_http_v1/demo_test.go‎

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"io/ioutil"
6+
"net/http"
7+
"net/http/httptest"
8+
"strings"
9+
"sync"
10+
"testing"
11+
)
12+
13+
func TestHandleRoot_Recorder(t *testing.T) {
14+
rw := httptest.NewRecorder()
15+
handleHi(rw, req(t, "GET / HTTP/1.0\r\n\r\n"))
16+
if !strings.Contains(rw.Body.String(), "visitor number") {
17+
t.Errorf("Unexpected output: %s", rw.Body)
18+
}
19+
}
20+
21+
func req(t testing.TB, v string) *http.Request {
22+
req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(v)))
23+
if err != nil {
24+
t.Fatal(err)
25+
}
26+
return req
27+
}
28+
29+
// 用真实的 client & server 测试
30+
func TestHandleHi_TestServer(t *testing.T) {
31+
ts := httptest.NewServer(http.HandlerFunc(handleHi))
32+
defer ts.Close()
33+
res, err := http.Get(ts.URL)
34+
t.Logf("URL: %s", ts.URL)
35+
if err != nil {
36+
t.Error(err)
37+
return
38+
}
39+
if g, w := res.Header.Get("Content-Type"), "text/html; charset=utf-8"; g != w {
40+
t.Errorf("Content-Type = %q; want %q", g, w)
41+
}
42+
slurp, err := ioutil.ReadAll(res.Body)
43+
defer res.Body.Close()
44+
45+
if err != nil {
46+
t.Error(err)
47+
return
48+
}
49+
t.Logf("Got: %s", slurp)
50+
}
51+
52+
// 测试并行
53+
func TestHandleHi_TestServer_Parallel(t *testing.T) {
54+
ts := httptest.NewServer(http.HandlerFunc(handleHi))
55+
defer ts.Close()
56+
var wg sync.WaitGroup
57+
for i := 0; i < 2; i++ {
58+
wg.Add(1)
59+
go func() {
60+
defer wg.Done()
61+
res, err := http.Get(ts.URL)
62+
if err != nil {
63+
t.Error(err)
64+
return
65+
}
66+
if g, w := res.Header.Get("Content-Type"), "text/html; charset=utf-8"; g != w {
67+
t.Errorf("Content-Type = %q; want %q", g, w)
68+
}
69+
slurp, err := ioutil.ReadAll(res.Body)
70+
defer res.Body.Close()
71+
if err != nil {
72+
t.Error(err)
73+
return
74+
}
75+
t.Logf("Got: %s", slurp)
76+
}()
77+
}
78+
wg.Wait()
79+
}
80+
81+
func BenchmarkHi(b *testing.B) {
82+
b.ReportAllocs()
83+
r := req(b, "GET / HTTP/1.0\r\n\r\n")
84+
for i := 0; i < b.N; i++ {
85+
rw := httptest.NewRecorder()
86+
handleHi(rw, r)
87+
}
88+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /