Here we are writing a simplistic HTTP server without using net/http package to reduce the size of the binary. * No --listen: 2.8MB * --listen with net/http: 5.7MB * --listen w/o net/http: 3.3MB
(conn net.Conn)
| 151 | // * --listen with net/http: 5.7MB |
| 152 | // * --listen w/o net/http: 3.3MB |
| 153 | func (server *httpServer) handleHttpRequest(conn net.Conn) string { |
| 154 | contentLength := 0 |
| 155 | apiKey := "" |
| 156 | var bodyBuilder strings.Builder |
| 157 | answer := func(code string, message string) string { |
| 158 | message += "\n" |
| 159 | return code + fmt.Sprintf("Content-Length: %d%s", len(message), crlf+crlf+message) |
| 160 | } |
| 161 | unauthorized := func(message string) string { |
| 162 | return answer(httpUnauthorized, message) |
| 163 | } |
| 164 | bad := func(message string) string { |
| 165 | return answer(httpBadRequest, message) |
| 166 | } |
| 167 | good := func(message string) string { |
| 168 | return answer(httpOk+jsonContentType, message) |
| 169 | } |
| 170 | conn.SetReadDeadline(time.Now().Add(httpReadTimeout)) |
| 171 | scanner := bufio.NewScanner(conn) |
| 172 | scanner.Split(func(data []byte, atEOF bool) (int, []byte, error) { |
| 173 | found := bytes.Index(data, []byte(crlf)) |
| 174 | if found >= 0 { |
| 175 | token := data[:found+len(crlf)] |
| 176 | return len(token), token, nil |
| 177 | } |
| 178 | if atEOF || bodyBuilder.Len()+len(data) >= contentLength { |
| 179 | return 0, data, bufio.ErrFinalToken |
| 180 | } |
| 181 | return 0, nil, nil |
| 182 | }) |
| 183 | |
| 184 | section := 0 |
| 185 | var getMatch []string |
| 186 | Loop: |
| 187 | for scanner.Scan() { |
| 188 | text := scanner.Text() |
| 189 | switch section { |
| 190 | case 0: // Request line |
| 191 | getMatch = getRegex.FindStringSubmatch(text) |
| 192 | if len(getMatch) == 0 && !strings.HasPrefix(text, "POST / HTTP") { |
| 193 | return bad("invalid request method") |
| 194 | } |
| 195 | section++ |
| 196 | case 1: // Request headers |
| 197 | if text == crlf { // End of headers |
| 198 | if len(getMatch) > 0 { |
| 199 | break Loop |
| 200 | } |
| 201 | if contentLength == 0 { |
| 202 | return bad("content-length header missing") |
| 203 | } |
| 204 | section++ |
| 205 | continue |
| 206 | } |
| 207 | pair := strings.SplitN(text, ":", 2) |
| 208 | if len(pair) == 2 { |
| 209 | switch strings.ToLower(pair[0]) { |
| 210 | case "content-length": |
no test coverage detected