Skip to content
This repository has been archived by the owner on Dec 17, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1155 from vania-pooh/master
Browse files Browse the repository at this point in the history
Switched to w3c standard compatible errors (fixes #1143)
  • Loading branch information
vania-pooh authored Nov 19, 2021
2 parents 124ae88 + 0466991 commit a20a4a8
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 23 deletions.
52 changes: 52 additions & 0 deletions jsonerror/jsonerror.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package jsonerror

import (
"encoding/json"
"fmt"
"net/http"
)

type SeleniumError struct {
Name string
Err error
Status int
}

func (se *SeleniumError) Error() string {
return fmt.Errorf("%s: %v", se.Name, se.Err).Error()
}

func newSeleniumError(name string, err error, status int) *SeleniumError {
return &SeleniumError{
Name: name,
Err: err,
Status: status,
}
}

func InvalidArgument(err error) *SeleniumError {
return newSeleniumError("invalid argument", err, http.StatusBadRequest)
}

func InvalidSessionID(err error) *SeleniumError {
return newSeleniumError("invalid session id", err, http.StatusNotFound)
}

func SessionNotCreated(err error) *SeleniumError {
return newSeleniumError("session not created", err, http.StatusInternalServerError)
}

func UnknownError(err error) *SeleniumError {
return newSeleniumError("unknown error", err, http.StatusInternalServerError)
}

func (se *SeleniumError) Encode(w http.ResponseWriter) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(se.Status)
_ = json.NewEncoder(w).Encode(map[string]interface{}{
"value": map[string]string{
"error": se.Name,
"message": se.Err.Error(),
},
})
}
4 changes: 3 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"encoding/json"
"flag"
"github.com/aerokube/selenoid/jsonerror"
"github.com/pkg/errors"
"log"
"net"
"net/http"
Expand Down Expand Up @@ -329,7 +331,7 @@ func handler() http.Handler {
selenium().ServeHTTP(w, r)
})
root.HandleFunc(paths.Error, func(w http.ResponseWriter, r *http.Request) {
util.JsonError(w, "Session timed out or not found", http.StatusNotFound)
jsonerror.InvalidSessionID(errors.New("session timed out or not found")).Encode(w)
})
root.HandleFunc(paths.Status, func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/json")
Expand Down
8 changes: 6 additions & 2 deletions protect/queue.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package protect

import (
"errors"
"github.com/aerokube/selenoid/jsonerror"
"log"
"math"
"net/http"
Expand Down Expand Up @@ -28,7 +30,8 @@ func (q *Queue) Try(next http.HandlerFunc) http.HandlerFunc {
<-q.limit
default:
if noWait {
util.JsonError(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
err := errors.New(http.StatusText(http.StatusTooManyRequests))
jsonerror.UnknownError(err).Encode(w)
return
}
}
Expand All @@ -46,7 +49,8 @@ func (q *Queue) Check(next http.HandlerFunc) http.HandlerFunc {
if q.disabled {
user, remote := util.RequestInfo(r)
log.Printf("[-] [QUEUE_IS_FULL] [%s] [%s]", user, remote)
util.JsonError(w, "Queue Is Full", http.StatusTooManyRequests)
err := errors.New("Queue Is Full")
jsonerror.UnknownError(err).Encode(w)
return
}
}
Expand Down
43 changes: 23 additions & 20 deletions selenoid.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/aerokube/selenoid/event"
"github.com/aerokube/selenoid/jsonerror"
"github.com/aerokube/selenoid/service"
"github.com/imdario/mergo"
"io"
Expand Down Expand Up @@ -114,7 +116,7 @@ func create(w http.ResponseWriter, r *http.Request) {
r.Body.Close()
if err != nil {
log.Printf("[%d] [ERROR_READING_REQUEST] [%v]", requestId, err)
util.JsonError(w, err.Error(), http.StatusBadRequest)
jsonerror.InvalidArgument(err).Encode(w)
queue.Drop()
return
}
Expand All @@ -128,7 +130,7 @@ func create(w http.ResponseWriter, r *http.Request) {
err = json.Unmarshal(body, &browser)
if err != nil {
log.Printf("[%d] [BAD_JSON_FORMAT] [%v]", requestId, err)
util.JsonError(w, err.Error(), http.StatusBadRequest)
jsonerror.InvalidArgument(err).Encode(w)
queue.Drop()
return
}
Expand All @@ -151,22 +153,22 @@ func create(w http.ResponseWriter, r *http.Request) {
sessionTimeout, err = getSessionTimeout(caps.SessionTimeout, maxTimeout, timeout)
if err != nil {
log.Printf("[%d] [BAD_SESSION_TIMEOUT] [%s]", requestId, caps.SessionTimeout)
util.JsonError(w, err.Error(), http.StatusBadRequest)
jsonerror.InvalidArgument(err).Encode(w)
queue.Drop()
return
}
resolution, err := getScreenResolution(caps.ScreenResolution)
if err != nil {
log.Printf("[%d] [BAD_SCREEN_RESOLUTION] [%s]", requestId, caps.ScreenResolution)
util.JsonError(w, err.Error(), http.StatusBadRequest)
jsonerror.InvalidArgument(err).Encode(w)
queue.Drop()
return
}
caps.ScreenResolution = resolution
videoScreenSize, err := getVideoScreenSize(caps.VideoScreenSize, resolution)
if err != nil {
log.Printf("[%d] [BAD_VIDEO_SCREEN_SIZE] [%s]", requestId, caps.VideoScreenSize)
util.JsonError(w, err.Error(), http.StatusBadRequest)
jsonerror.InvalidArgument(err).Encode(w)
queue.Drop()
return
}
Expand All @@ -186,14 +188,14 @@ func create(w http.ResponseWriter, r *http.Request) {
}
if !ok {
log.Printf("[%d] [ENVIRONMENT_NOT_AVAILABLE] [%s] [%s]", requestId, caps.BrowserName(), caps.Version)
util.JsonError(w, "Requested environment is not available", http.StatusBadRequest)
jsonerror.InvalidArgument(errors.New("Requested environment is not available")).Encode(w)
queue.Drop()
return
}
startedService, err := starter.StartWithCancel()
if err != nil {
log.Printf("[%d] [SERVICE_STARTUP_FAILED] [%v]", requestId, err)
util.JsonError(w, err.Error(), http.StatusInternalServerError)
jsonerror.SessionNotCreated(err).Encode(w)
queue.Drop()
return
}
Expand Down Expand Up @@ -228,7 +230,7 @@ func create(w http.ResponseWriter, r *http.Request) {
}
err := fmt.Errorf("New session attempts retry count exceeded")
log.Printf("[%d] [SESSION_FAILED] [%s] [%s]", requestId, u.String(), err)
util.JsonError(w, err.Error(), http.StatusInternalServerError)
jsonerror.UnknownError(err).Encode(w)
case context.Canceled:
log.Printf("[%d] [CLIENT_DISCONNECTED] [%s] [%s] [%.2fs]", requestId, user, remote, util.SecondsSince(sessionStartTime))
}
Expand All @@ -242,7 +244,7 @@ func create(w http.ResponseWriter, r *http.Request) {
rsp.Body.Close()
}
log.Printf("[%d] [SESSION_FAILED] [%s] [%s]", requestId, u.String(), err)
util.JsonError(w, err.Error(), http.StatusInternalServerError)
jsonerror.SessionNotCreated(err).Encode(w)
queue.Drop()
cancel()
return
Expand Down Expand Up @@ -415,7 +417,7 @@ func getScreenResolution(input string) (string, error) {
return fmt.Sprintf("%sx24", input), nil
}
return "", fmt.Errorf(
"Malformed screenResolution capability: %s. Correct format is WxH (1920x1080) or WxHxD (1920x1080x24).",
"malformed screenResolution capability: %s, correct format is WxH (1920x1080) or WxHxD (1920x1080x24)",
input,
)
}
Expand All @@ -430,7 +432,7 @@ func getVideoScreenSize(videoScreenSize string, screenResolution string) (string
return videoScreenSize, nil
}
return "", fmt.Errorf(
"Malformed videoScreenSize capability: %s. Correct format is WxH (1920x1080).",
"malformed videoScreenSize capability: %s, correct format is WxH (1920x1080)",
videoScreenSize,
)
}
Expand Down Expand Up @@ -512,7 +514,7 @@ func proxy(w http.ResponseWriter, r *http.Request) {
}
seUploadPath, uploadPath := "/se/file", "/file"
if strings.HasSuffix(r.URL.Path, seUploadPath) {
r.URL.Path = strings.TrimSuffix(r.URL.Path, seUploadPath)+uploadPath
r.URL.Path = strings.TrimSuffix(r.URL.Path, seUploadPath) + uploadPath
}
r.URL.Host, r.URL.Path = sess.URL.Host, path.Clean(sess.URL.Path+r.URL.Path)
r.Host = "localhost"
Expand Down Expand Up @@ -556,7 +558,7 @@ func reverseProxy(hostFn func(sess *session.Session) string, status string) func
ErrorHandler: defaultErrorHandler(requestId),
}).ServeHTTP(w, r)
} else {
util.JsonError(w, fmt.Sprintf("Unknown session %s", sid), http.StatusNotFound)
jsonerror.InvalidSessionID(fmt.Errorf("unknown session %s", sid)).Encode(w)
log.Printf("[%d] [SESSION_NOT_FOUND] [%s]", requestId, sid)
}
}
Expand All @@ -573,41 +575,42 @@ func fileUpload(w http.ResponseWriter, r *http.Request) {
}
err := json.NewDecoder(r.Body).Decode(&jsonRequest)
if err != nil {
util.JsonError(w, err.Error(), http.StatusBadRequest)
jsonerror.InvalidArgument(err).Encode(w)
return
}
z, err := zip.NewReader(bytes.NewReader(jsonRequest.File), int64(len(jsonRequest.File)))
if err != nil {
util.JsonError(w, err.Error(), http.StatusBadRequest)
jsonerror.InvalidArgument(err).Encode(w)
return
}
if len(z.File) != 1 {
util.JsonError(w, fmt.Sprintf("Expected there to be only 1 file. There were: %d", len(z.File)), http.StatusBadRequest)
err := fmt.Errorf("expected there to be only 1 file. There were: %d", len(z.File))
jsonerror.InvalidArgument(err).Encode(w)
return
}
file := z.File[0]
src, err := file.Open()
if err != nil {
util.JsonError(w, err.Error(), http.StatusBadRequest)
jsonerror.InvalidArgument(err).Encode(w)
return
}
defer src.Close()
dir := r.Header.Get("X-Selenoid-File")
err = os.MkdirAll(dir, 0755)
if err != nil {
util.JsonError(w, err.Error(), http.StatusInternalServerError)
jsonerror.UnknownError(err).Encode(w)
return
}
fileName := filepath.Join(dir, file.Name)
dst, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
util.JsonError(w, err.Error(), http.StatusInternalServerError)
jsonerror.UnknownError(err).Encode(w)
return
}
defer dst.Close()
_, err = io.Copy(dst, src)
if err != nil {
util.JsonError(w, err.Error(), http.StatusInternalServerError)
jsonerror.UnknownError(err).Encode(w)
return
}

Expand Down

0 comments on commit a20a4a8

Please sign in to comment.