| 338 | } |
| 339 | |
| 340 | func buildHTTPRequest( |
| 341 | ctx context.Context, |
| 342 | connectRequest *pogs.ConnectRequest, |
| 343 | body io.ReadCloser, |
| 344 | connIndex uint8, |
| 345 | log *zerolog.Logger, |
| 346 | ) (*tracing.TracedHTTPRequest, error) { |
| 347 | metadata := connectRequest.MetadataMap() |
| 348 | dest := connectRequest.Dest |
| 349 | method := metadata[HTTPMethodKey] |
| 350 | host := metadata[HTTPHostKey] |
| 351 | isWebsocket := connectRequest.Type == pogs.ConnectionTypeWebsocket |
| 352 | |
| 353 | req, err := http.NewRequestWithContext(ctx, method, dest, body) |
| 354 | if err != nil { |
| 355 | return nil, err |
| 356 | } |
| 357 | |
| 358 | req.Host = host |
| 359 | for _, metadata := range connectRequest.Metadata { |
| 360 | if strings.Contains(metadata.Key, HTTPHeaderKey) { |
| 361 | // metadata.Key is off the format httpHeaderKey:<HTTPHeader> |
| 362 | httpHeaderKey := strings.Split(metadata.Key, ":") |
| 363 | if len(httpHeaderKey) != 2 { |
| 364 | return nil, fmt.Errorf("header Key: %s malformed", metadata.Key) |
| 365 | } |
| 366 | req.Header.Add(httpHeaderKey[1], metadata.Val) |
| 367 | } |
| 368 | } |
| 369 | // Go's http.Client automatically sends chunked request body if this value is not set on the |
| 370 | // *http.Request struct regardless of header: |
| 371 | // https://go.googlesource.com/go/+/go1.8rc2/src/net/http/transfer.go#154. |
| 372 | if err := setContentLength(req); err != nil { |
| 373 | return nil, fmt.Errorf("Error setting content-length: %w", err) |
| 374 | } |
| 375 | |
| 376 | // Go's client defaults to chunked encoding after a 200ms delay if the following cases are true: |
| 377 | // * the request body blocks |
| 378 | // * the content length is not set (or set to -1) |
| 379 | // * the method doesn't usually have a body (GET, HEAD, DELETE, ...) |
| 380 | // * there is no transfer-encoding=chunked already set. |
| 381 | // So, if transfer cannot be chunked and content length is 0, we dont set a request body. |
| 382 | if !isWebsocket && !isTransferEncodingChunked(req) && req.ContentLength == 0 { |
| 383 | req.Body = http.NoBody |
| 384 | } |
| 385 | stripWebsocketUpgradeHeader(req) |
| 386 | |
| 387 | // Check for tracing on request |
| 388 | tracedReq := tracing.NewTracedHTTPRequest(req, connIndex, log) |
| 389 | return tracedReq, err |
| 390 | } |
| 391 | |
| 392 | func setContentLength(req *http.Request) error { |
| 393 | var err error |