From 2cdcde51e5298315908d52d0bf3a2a27b75c954a Mon Sep 17 00:00:00 2001 From: lhchavez Date: Mon, 1 Nov 2021 07:01:51 -0700 Subject: [PATCH] Fix the status parsing This should now make it possible to let the caller know that a non-OK status was returned. --- fcgi.go | 62 ++++++++++++++++++++++++++++----------------------------- main.go | 18 +++++++++++------ 2 files changed, 43 insertions(+), 37 deletions(-) diff --git a/fcgi.go b/fcgi.go index 1287be5..c2e8bbd 100644 --- a/fcgi.go +++ b/fcgi.go @@ -332,12 +332,18 @@ type streamReader struct { func (w *streamReader) Read(p []byte) (n int, err error) { if len(p) > 0 { - if len(w.buf) == 0 { + for len(w.buf) == 0 { rec := &record{} - w.buf, err = rec.read(w.c.rwc) + var buf []byte + buf, err = rec.read(w.c.rwc) if err != nil { return } + if rec.h.Type != FCGI_STDOUT { + // Skip this record. + continue + } + w.buf = buf } n = len(p) @@ -398,35 +404,6 @@ func (this *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http. rb := bufio.NewReader(r) tp := textproto.NewReader(rb) resp = new(http.Response) - // Parse the first line of the response. - line, err := tp.ReadLine() - if err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return nil, err - } - if i := strings.IndexByte(line, ' '); i == -1 { - err = &badStringError{"malformed HTTP response", line} - } else { - resp.Proto = line[:i] - resp.Status = strings.TrimLeft(line[i+1:], " ") - } - statusCode := resp.Status - if i := strings.IndexByte(resp.Status, ' '); i != -1 { - statusCode = resp.Status[:i] - } - if len(statusCode) != 3 { - err = &badStringError{"malformed HTTP status code", statusCode} - } - resp.StatusCode, err = strconv.Atoi(statusCode) - if err != nil || resp.StatusCode < 0 { - err = &badStringError{"malformed HTTP status code", statusCode} - } - var ok bool - if resp.ProtoMajor, resp.ProtoMinor, ok = http.ParseHTTPVersion(resp.Proto); !ok { - err = &badStringError{"malformed HTTP version", resp.Proto} - } // Parse the response headers. mimeHeader, err := tp.ReadMIMEHeader() if err != nil { @@ -436,6 +413,29 @@ func (this *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http. return nil, err } resp.Header = http.Header(mimeHeader) + resp.StatusCode = http.StatusOK + resp.Status = "OK" + resp.ProtoMajor = 1 + resp.ProtoMinor = 1 + if status, ok := resp.Header["Status"]; ok { + delete(resp.Header, "Status") + + line := status[0] + if i := strings.IndexByte(line, ' '); i == -1 { + err = &badStringError{"malformed HTTP response", line} + } else { + resp.Status = strings.Trim(line[:i+1], " ") + statusCode := strings.Trim(line[:i], " ") + if len(statusCode) != 3 { + err = &badStringError{"malformed HTTP status code", statusCode} + } else { + resp.StatusCode, err = strconv.Atoi(statusCode) + if err != nil || resp.StatusCode < 0 { + err = &badStringError{"malformed HTTP status code", statusCode} + } + } + } + } // TODO: fixTransferEncoding ? resp.TransferEncoding = resp.Header["Transfer-Encoding"] resp.ContentLength, _ = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64) diff --git a/main.go b/main.go index 9532741..2df6c43 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "log" "net/http" "os" + "path" "sort" "sync" "time" @@ -43,6 +44,11 @@ func worker( return } + if resp.StatusCode != http.StatusOK { + log.Printf("ERR: http: %v", resp.StatusCode) + return + } + _, err = ioutil.ReadAll(resp.Body) resp.Body.Close() if err != nil { @@ -58,7 +64,7 @@ func main() { fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] \n", os.Args[0]) flag.PrintDefaults() } - script := flag.String("script", "/index.php", "script to execute") + script := flag.String("script", "index.php", "script to execute") network := flag.String("network", "tcp", "network to dial (net or unix)") address := flag.String("address", "localhost:9000", "address to dial") workerCount := flag.Int("workers", 4, "number of worker goroutines") @@ -74,7 +80,7 @@ func main() { } req := map[string]string{ - "SCRIPT_FILENAME": "/opt/omegaup/frontend/www" + *script, + "SCRIPT_FILENAME": path.Join("/opt/omegaup/frontend/www", *script), "GATEWAY_INTERFACE": "CGI/1.1", "SERVER_SOFTWARE": "go / fcgiclient", "REMOTE_ADDR": "127.0.0.1", @@ -105,13 +111,13 @@ func main() { averageLatency += latency latencies = append(latencies, latency) } - sort.Slice(latencies, func(i, j int) bool { return latencies[i] < latencies[j] }) - averageLatency /= time.Duration(len(latencies)) log.Printf("Done sending %d requests", len(latencies)) if len(latencies) == 0 { return } + sort.Slice(latencies, func(i, j int) bool { return latencies[i] < latencies[j] }) + averageLatency /= time.Duration(len(latencies)) log.Printf("Mean latency: %v", averageLatency) log.Printf("Min latency: %v", latencies[0]) log.Printf("50th latency: %v", latencies[len(latencies)/2]) @@ -133,7 +139,7 @@ func main() { } if *verbose { - fmt.Fprintf(os.Stderr, "HTTP %d/%d %d\n", resp.ProtoMajor, resp.ProtoMinor, resp.StatusCode) + fmt.Fprintf(os.Stderr, "HTTP/%d.%d %d\n", resp.ProtoMajor, resp.ProtoMinor, resp.StatusCode) for k, values := range resp.Header { for _, v := range values { fmt.Fprintf(os.Stderr, "%v: %v\n", k, v) @@ -149,7 +155,7 @@ func main() { } os.Stdout.Write(contents) if resp.StatusCode != 0 && resp.StatusCode != http.StatusOK { - log.Fatalf("Status code: %v", resp.StatusCode) + os.Exit(1) } default: