diff --git a/selenoid.go b/selenoid.go index f914a128..1f9a2ee2 100644 --- a/selenoid.go +++ b/selenoid.go @@ -281,12 +281,25 @@ func create(w http.ResponseWriter, r *http.Request) { w.WriteHeader(resp.StatusCode) } } else { - tee := io.TeeReader(resp.Body, w) - w.WriteHeader(resp.StatusCode) - json.NewDecoder(tee).Decode(&s) - if s.ID == "" { - s.ID = s.Value.ID + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Printf("[%d] [ERROR_READING_RESPONSE] [%v]", requestId, err) + queue.Drop() + cancel() + return } + newBody, sessionId, err := processBody(body, r.Host) + if err != nil { + log.Printf("[%d] [ERROR_PROCESSING_RESPONSE] [%v]", requestId, err) + queue.Drop() + cancel() + return + } + resp.Body = io.NopCloser(bytes.NewReader(newBody)) + resp.ContentLength = int64(len(newBody)) + w.WriteHeader(resp.StatusCode) + w.Write(newBody) + s.ID = sessionId } if s.ID == "" { log.Printf("[%d] [SESSION_FAILED] [%s] [%s]", requestId, u.String(), resp.Status) @@ -393,6 +406,30 @@ func removeSelenoidOptions(input []byte) []byte { return ret } +func processBody(input []byte, host string) ([]byte, string, error) { + body := make(map[string]interface{}) + sessionId := "" + err := json.Unmarshal(input, &body) + if err != nil { + return nil, sessionId, fmt.Errorf("parse body response: %v", err) + } + if raw, ok := body["value"]; ok { + if v, ok := raw.(map[string]interface{}); ok { + if raw, ok := v["capabilities"]; ok { + if c, ok := raw.(map[string]interface{}); ok { + sessionId = v["sessionId"].(string) + c["se:cdp"] = fmt.Sprintf("ws://%s/devtools/%s/", host, sessionId) + } + } + } + } + ret, err := json.Marshal(body) + if err != nil { + return nil, sessionId, fmt.Errorf("marshal response: %v", err) + } + return ret, sessionId, nil +} + func preprocessSessionId(sid string) string { if ggrHost != nil { return ggrHost.Sum() + sid diff --git a/selenoid_test.go b/selenoid_test.go index a541cacf..efeac113 100644 --- a/selenoid_test.go +++ b/selenoid_test.go @@ -916,6 +916,30 @@ func TestDevtools(t *testing.T) { queue.Release() } +func TestAddedSeCdpCapability(t *testing.T) { + manager = &HTTPTest{Handler: Selenium()} + + resp, err := http.Post(With(srv.URL).Path("/wd/hub/session"), "", bytes.NewReader([]byte("{}"))) + AssertThat(t, err, Is{nil}) + + var sess map[string]string + AssertThat(t, resp, AllOf{Code{http.StatusOK}, IsJson{&sess}}) + + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + + conn, err := rpcc.DialContext(ctx, sess["se:cdp"]) + AssertThat(t, err, Is{nil}) + defer conn.Close() + + c := cdp.NewClient(conn) + err = c.Page.Enable(ctx) + AssertThat(t, err, Is{nil}) + + sessions.Remove(sess["sessionId"]) + queue.Release() +} + func TestParseGgrHost(t *testing.T) { h := parseGgrHost("some-host.example.com:4444") AssertThat(t, h.Name, EqualTo{"some-host.example.com"})