package server import ( "bufio" "errors" "strings" ) type Request struct { Method string URL string HTTPVersion string Headers map[string]string Body string } var ( ErrMalformedRequest = errors.New("malformed HTTP request") ErrInvalidMethod = errors.New("invalid HTTP method") ) func ParseRequest(reader *bufio.Reader) (*Request, error) { requestLine, err := reader.ReadString('\n') if err != nil { return nil, ErrMalformedRequest } requestLine = strings.TrimSpace(requestLine) if requestLine == "" { return nil, ErrMalformedRequest } parts := strings.Fields(requestLine) if len(parts) != 3 { return nil, ErrMalformedRequest } req := &Request{ Method: parts[0], URL: parts[1], HTTPVersion: parts[2], Headers: make(map[string]string), } for { headerLine, err := reader.ReadString('\n') if err != nil { break } headerLine = strings.TrimSpace(headerLine) if headerLine == "" { break } parts := strings.SplitN(headerLine, ":", 2) if len(parts) == 2 { key := strings.TrimSpace(parts[0]) value := strings.TrimSpace(parts[1]) req.Headers[key] = value } } return req, nil } func (r *Request) IsValid() bool { switch r.Method { case "GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH": return true default: return false } } func (r *Request) IsGET() bool { return r.Method == "GET" } func (r *Request) GetPath() string { if r.URL == "" || r.URL == "/" { return "/index.html" } path := strings.SplitN(r.URL, "?", 2)[0] if path == "/" { return "/index.html" } if strings.HasPrefix(path, "/") { return path } return "/" + path }