99 "fmt"
1010 "log/slog"
1111 "maps"
12+ "net/http"
1213 "os"
1314 "os/exec"
1415 "path/filepath"
@@ -19,7 +20,9 @@ import (
1920 "time"
2021
2122 "github.com/chromedp/cdproto/browser"
23+ "github.com/chromedp/cdproto/cdp"
2224 "github.com/chromedp/cdproto/emulation"
25+ "github.com/chromedp/cdproto/fetch"
2326 "github.com/chromedp/cdproto/network"
2427 "github.com/chromedp/cdproto/page"
2528 "github.com/chromedp/chromedp"
@@ -233,6 +236,7 @@ func (s *BrowserService) Render(ctx context.Context, url string, printer Printer
233236 fileChan := make (chan []byte , 1 ) // buffered: we don't want the browser to stick around while we try to export this value.
234237 actions := []chromedp.Action {
235238 tracingAction ("network.Enable" , network .Enable ()),
239+ tracingAction ("fetch.Enable" , fetch .Enable ()), // required by handleNetworkEvents
236240 tracingAction ("SetPageScaleFactor" , emulation .SetPageScaleFactor (cfg .PageScaleFactor )),
237241 tracingAction ("EmulateViewport" , chromedp .EmulateViewport (int64 (cfg .MinWidth ), int64 (cfg .MinHeight ), orientation )),
238242 setHeaders (browserCtx , cfg .Headers ),
@@ -392,6 +396,34 @@ func (s *BrowserService) handleNetworkEvents(browserCtx context.Context) {
392396 // See the docs of ListenTarget for more.
393397
394398 switch e := ev .(type ) {
399+ case * fetch.EventRequestPaused :
400+ go func () {
401+ if sc := trace .SpanFromContext (browserCtx ); sc != nil && sc .IsRecording () {
402+ otel .GetTextMapPropagator ().Inject (browserCtx , networkHeadersCarrier (e .Request .Headers ))
403+ }
404+
405+ hdrs := make ([]* fetch.HeaderEntry , 0 , len (e .Request .Headers ))
406+ for k , v := range e .Request .Headers {
407+ hdrs = append (hdrs , & fetch.HeaderEntry {Name : k , Value : fmt .Sprintf ("%v" , v )})
408+ }
409+
410+ ctx , span := tracer .Start (browserCtx , "fetch.ContinueRequest" ,
411+ trace .WithAttributes (
412+ attribute .String ("requestID" , string (e .RequestID )),
413+ attribute .String ("url" , e .Request .URL ),
414+ attribute .String ("method" , e .Request .Method ),
415+ attribute .Int ("headers" , len (e .Request .Headers )),
416+ ))
417+ defer span .End ()
418+ cdpCtx := chromedp .FromContext (browserCtx )
419+ ctx = cdp .WithExecutor (ctx , cdpCtx .Target )
420+
421+ if err := fetch .ContinueRequest (e .RequestID ).WithHeaders (hdrs ).Do (ctx ); err != nil {
422+ span .SetStatus (codes .Error , err .Error ())
423+ slog .DebugContext (ctx , "failed to continue request" , "requestID" , e .RequestID , "error" , err )
424+ }
425+ }()
426+
395427 case * network.EventRequestWillBeSent :
396428 mu .Lock ()
397429 defer mu .Unlock ()
@@ -414,17 +446,20 @@ func (s *BrowserService) handleNetworkEvents(browserCtx context.Context) {
414446 if ! ok {
415447 return
416448 }
449+ statusText := e .Response .StatusText
450+ if statusText == "" {
451+ statusText = http .StatusText (int (e .Response .Status ))
452+ }
417453 span .SetAttributes (
418454 attribute .Int ("status" , int (e .Response .Status )),
419- attribute .String ("statusText" , e . Response . StatusText ),
455+ attribute .String ("statusText" , statusText ),
420456 attribute .String ("mimeType" , e .Response .MimeType ),
421457 attribute .String ("protocol" , e .Response .Protocol ),
422- attribute .String ("contentType" , fmt .Sprintf ("%v" , e .Response .Headers ["Content-Type" ])),
423458 )
424459 if e .Response .Status >= 400 {
425- span .SetStatus (codes .Error , e .Response .StatusText )
460+ span .SetStatus (codes .Error , fmt . Sprintf ( "%d %s" , e .Response .Status , statusText ) )
426461 } else {
427- span .SetStatus (codes .Ok , e .Response .StatusText )
462+ span .SetStatus (codes .Ok , fmt . Sprintf ( "%d %s" , e .Response .Status , statusText ) )
428463 }
429464 span .End (trace .WithTimestamp (e .Timestamp .Time ()))
430465 delete (requests , e .RequestID ) // no point keeping it around anymore.
@@ -751,13 +786,6 @@ func NewPNGPrinter(opts ...PNGPrinterOption) (*pngPrinter, error) {
751786}
752787
753788func setHeaders (browserCtx context.Context , headers network.Headers ) chromedp.Action {
754- if sc := trace .SpanFromContext (browserCtx ); sc != nil && sc .IsRecording () {
755- if headers == nil {
756- headers = make (network.Headers )
757- }
758- otel .GetTextMapPropagator ().Inject (browserCtx , networkHeadersCarrier (headers ))
759- }
760-
761789 return chromedp .ActionFunc (func (ctx context.Context ) error {
762790 tracer := tracer (ctx )
763791 ctx , span := tracer .Start (ctx , "setHeaders" ,
0 commit comments