summaryrefslogtreecommitdiff
path: root/pkg/worker_handler/handler.go
diff options
context:
space:
mode:
authorValery Piashchynski <[email protected]>2021-09-16 21:46:50 +0300
committerGitHub <[email protected]>2021-09-16 21:46:50 +0300
commit3581b45f237a3f7aa29591ceb2bf6f4a4642a2f5 (patch)
treee723b19ec1ac16b7ccc7b3c2da69d4a416d63d81 /pkg/worker_handler/handler.go
parent337d292dd2d6ff0a555098b1970d8194d8df8bc2 (diff)
parent823d831b57b75f70c7c3bbbee355f2016633bb3b (diff)
[#803]: feat(plugins): move plugins to a separate repositoryv2.5.0-alpha.2
[#803]: feat(plugins): move plugins to a separate repository
Diffstat (limited to 'pkg/worker_handler/handler.go')
-rw-r--r--pkg/worker_handler/handler.go246
1 files changed, 0 insertions, 246 deletions
diff --git a/pkg/worker_handler/handler.go b/pkg/worker_handler/handler.go
deleted file mode 100644
index fc03563b..00000000
--- a/pkg/worker_handler/handler.go
+++ /dev/null
@@ -1,246 +0,0 @@
-package handler
-
-import (
- "net"
- "net/http"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "github.com/spiral/errors"
- "github.com/spiral/roadrunner/v2/pkg/events"
- "github.com/spiral/roadrunner/v2/pkg/pool"
- "github.com/spiral/roadrunner/v2/plugins/http/config"
- "github.com/spiral/roadrunner/v2/plugins/logger"
-)
-
-// MB is 1024 bytes
-const MB uint64 = 1024 * 1024
-
-// ErrorEvent represents singular http error event.
-type ErrorEvent struct {
- // Request contains client request, must not be stored.
- Request *http.Request
-
- // Error - associated error, if any.
- Error error
-
- // event timings
- start time.Time
- elapsed time.Duration
-}
-
-// Elapsed returns duration of the invocation.
-func (e *ErrorEvent) Elapsed() time.Duration {
- return e.elapsed
-}
-
-// ResponseEvent represents singular http response event.
-type ResponseEvent struct {
- // Request contains client request, must not be stored.
- Request *Request
-
- // Response contains service response.
- Response *Response
-
- // event timings
- start time.Time
- elapsed time.Duration
-}
-
-// Elapsed returns duration of the invocation.
-func (e *ResponseEvent) Elapsed() time.Duration {
- return e.elapsed
-}
-
-// Handler serves http connections to underlying PHP application using PSR-7 protocol. Context will include request headers,
-// parsed files and query, payload will include parsed form dataTree (if any).
-type Handler struct {
- maxRequestSize uint64
- uploads config.Uploads
- trusted config.Cidrs
- log logger.Logger
- pool pool.Pool
- mul sync.Mutex
- lsn []events.Listener
- internalHTTPCode uint64
-}
-
-// NewHandler return handle interface implementation
-func NewHandler(maxReqSize uint64, internalHTTPCode uint64, uploads config.Uploads, trusted config.Cidrs, pool pool.Pool) (*Handler, error) {
- if pool == nil {
- return nil, errors.E(errors.Str("pool should be initialized"))
- }
- return &Handler{
- maxRequestSize: maxReqSize * MB,
- uploads: uploads,
- pool: pool,
- trusted: trusted,
- internalHTTPCode: internalHTTPCode,
- }, nil
-}
-
-// AddListener attaches handler event controller.
-func (h *Handler) AddListener(l ...events.Listener) {
- h.mul.Lock()
- defer h.mul.Unlock()
-
- h.lsn = l
-}
-
-// mdwr serve using PSR-7 requests passed to underlying application. Attempts to serve static files first if enabled.
-func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- const op = errors.Op("serve_http")
- start := time.Now()
-
- // validating request size
- if h.maxRequestSize != 0 {
- const op = errors.Op("http_handler_max_size")
- if length := r.Header.Get("content-length"); length != "" {
- // try to parse the value from the `content-length` header
- size, err := strconv.ParseInt(length, 10, 64)
- if err != nil {
- // if got an error while parsing -> assign 500 code to the writer and return
- http.Error(w, "", 500)
- h.sendEvent(ErrorEvent{Request: r, Error: errors.E(op, errors.Str("error while parsing value from the `content-length` header")), start: start, elapsed: time.Since(start)})
- return
- }
-
- if size > int64(h.maxRequestSize) {
- h.sendEvent(ErrorEvent{Request: r, Error: errors.E(op, errors.Str("request body max size is exceeded")), start: start, elapsed: time.Since(start)})
- http.Error(w, errors.E(op, errors.Str("request body max size is exceeded")).Error(), http.StatusBadRequest)
- return
- }
- }
- }
-
- req, err := NewRequest(r, h.uploads)
- if err != nil {
- // if pipe is broken, there is no sense to write the header
- // in this case we just report about error
- if err == errEPIPE {
- h.sendEvent(ErrorEvent{Request: r, Error: err, start: start, elapsed: time.Since(start)})
- return
- }
-
- http.Error(w, errors.E(op, err).Error(), 500)
- h.sendEvent(ErrorEvent{Request: r, Error: errors.E(op, err), start: start, elapsed: time.Since(start)})
- return
- }
-
- // proxy IP resolution
- h.resolveIP(req)
-
- req.Open(h.log)
- defer req.Close(h.log)
-
- p, err := req.Payload()
- if err != nil {
- h.handleError(w, r, start, err)
- h.sendEvent(ErrorEvent{Request: r, Error: errors.E(op, err), start: start, elapsed: time.Since(start)})
- return
- }
-
- rsp, err := h.pool.Exec(p)
- if err != nil {
- h.handleError(w, r, start, err)
- h.sendEvent(ErrorEvent{Request: r, Error: errors.E(op, err), start: start, elapsed: time.Since(start)})
- return
- }
-
- resp, err := NewResponse(rsp)
- if err != nil {
- h.handleError(w, r, start, err)
- h.sendEvent(ErrorEvent{Request: r, Error: errors.E(op, err), start: start, elapsed: time.Since(start)})
- return
- }
-
- h.handleResponse(req, resp, start)
- err = resp.Write(w)
- if err != nil {
- http.Error(w, errors.E(op, err).Error(), 500)
- h.sendEvent(ErrorEvent{Request: r, Error: errors.E(op, err), start: start, elapsed: time.Since(start)})
- }
-}
-
-// handleError will handle internal RR errors and return 500
-func (h *Handler) handleError(w http.ResponseWriter, r *http.Request, start time.Time, err error) {
- const op = errors.Op("handle_error")
- // internal error types, user should not see them
- if errors.Is(errors.SoftJob, err) ||
- errors.Is(errors.WatcherStopped, err) ||
- errors.Is(errors.WorkerAllocate, err) ||
- errors.Is(errors.NoFreeWorkers, err) ||
- errors.Is(errors.ExecTTL, err) ||
- errors.Is(errors.IdleTTL, err) ||
- errors.Is(errors.TTL, err) ||
- errors.Is(errors.Encode, err) ||
- errors.Is(errors.Decode, err) ||
- errors.Is(errors.Network, err) {
- // write an internal server error
- w.WriteHeader(int(h.internalHTTPCode))
- h.sendEvent(ErrorEvent{Request: r, Error: errors.E(op, err), start: start, elapsed: time.Since(start)})
- }
-}
-
-// handleResponse triggers response event.
-func (h *Handler) handleResponse(req *Request, resp *Response, start time.Time) {
- h.sendEvent(ResponseEvent{Request: req, Response: resp, start: start, elapsed: time.Since(start)})
-}
-
-// sendEvent invokes event handler if any.
-func (h *Handler) sendEvent(event interface{}) {
- if h.lsn != nil {
- for i := range h.lsn {
- // do not block the pipeline
- // TODO not a good approach, redesign event bus
- i := i
- go func() {
- h.lsn[i](event)
- }()
- }
- }
-}
-
-// get real ip passing multiple proxy
-func (h *Handler) resolveIP(r *Request) {
- if h.trusted.IsTrusted(r.RemoteAddr) == false { //nolint:gosimple
- return
- }
-
- if r.Header.Get("X-Forwarded-For") != "" {
- ips := strings.Split(r.Header.Get("X-Forwarded-For"), ",")
- ipCount := len(ips)
-
- for i := ipCount - 1; i >= 0; i-- {
- addr := strings.TrimSpace(ips[i])
- if net.ParseIP(addr) != nil {
- r.RemoteAddr = addr
- return
- }
- }
-
- return
- }
-
- // The logic here is the following:
- // In general case, we only expect X-Real-Ip header. If it exist, we get the IP address from header and set request Remote address
- // But, if there is no X-Real-Ip header, we also trying to check CloudFlare headers
- // True-Client-IP is a general CF header in which copied information from X-Real-Ip in CF.
- // CF-Connecting-IP is an Enterprise feature and we check it last in order.
- // This operations are near O(1) because Headers struct are the map type -> type MIMEHeader map[string][]string
- if r.Header.Get("X-Real-Ip") != "" {
- r.RemoteAddr = FetchIP(r.Header.Get("X-Real-Ip"))
- return
- }
-
- if r.Header.Get("True-Client-IP") != "" {
- r.RemoteAddr = FetchIP(r.Header.Get("True-Client-IP"))
- return
- }
-
- if r.Header.Get("CF-Connecting-IP") != "" {
- r.RemoteAddr = FetchIP(r.Header.Get("CF-Connecting-IP"))
- }
-}