package main import ( "bufio" "errors" "fmt" "io" "log" "net" "strings" ) type HttpRequest struct { Method string Url string Proto string Version string Headers map[string]string Body string } type HttpResponse struct { Proto string Code int Status string Body string } func checkMethod(m string) error { switch m { case "GET": case "POST": case "PUT": case "HEAD": case "DELETE": case "OPTIONS": default: return errors.New("Unknown method") } return nil } func checkProto(p string) error { switch p { case "HTTP/1.1": case "HTTP/1.0": default: return errors.New("Unknown proto") } return nil } func (req *HttpRequest) parseRequestLine(line string) error { parts := strings.Fields(line) if len(parts) != 3 { return errors.New("Invalid request line") } for i, p := range parts { switch i { case 0: if err := checkMethod(p); err != nil { return err } req.Method = p case 1: req.Url = p case 2: if err := checkProto(p); err != nil { return err } req.Proto = p } } req.Headers = make(map[string]string) return nil } func (req *HttpRequest) parseHeader(line string) error { parts := strings.Fields(line) if len(parts) < 2 { return errors.New("Invalid header") } name := parts[0] if !strings.HasSuffix(name, ":") { return errors.New("Invalid header") } value := strings.Join(parts[1:], " ") req.Headers[name[:len(name)-1]] = value return nil } func (req *HttpRequest) appendBody(line string) error { req.Body += line + "\n" return nil } func (req *HttpRequest) handleRequest() *HttpResponse { resp := &HttpResponse{ Proto: req.Proto, Code: 200, Status: "OK", Body: "URL = " + req.Url + "\n", } return resp } func (resp *HttpResponse) String() string { return fmt.Sprintf("%s %d %s\r\nContent-Length: %d\r\n\r\n%s", resp.Proto, resp.Code, resp.Status, len(resp.Body), resp.Body) } func handle(conn net.Conn) { defer conn.Close() req := new(HttpRequest) scanner := bufio.NewScanner(conn) requestLine := true headers := false for scanner.Scan() { line := scanner.Text() if requestLine { fmt.Println("Request line:", line) if err := req.parseRequestLine(line); err != nil { log.Fatalln("error request line", err) // TODO response error } requestLine, headers = false, true } else if headers { if line == "" { fmt.Println("End headers") headers = false break } else { fmt.Println("Header:", line) if err := req.parseHeader(line); err != nil { log.Println("error header", err) } } } else { break /* if err := req.appendBody(line); err != nil { log.Println("error body", err) } */ } } resp := req.handleRequest() io.WriteString(conn, resp.String()) } func main() { server, err := net.Listen("tcp", ":9000") if err != nil { log.Fatalln(err) } defer server.Close() for { conn, err := server.Accept() if err != nil { log.Fatalln(err) } go handle(conn) } }