// TBD: Extract more info func UnpackProxyRequest(raw []byte) (*http.Request, error) { var ( mh codec.MsgpackHandle h = &mh ) var v []interface{} mh.SliceType = reflect.TypeOf(Headers(nil)) codec.NewDecoderBytes(raw, h).Decode(&v) r, err := http.NewRequest(string(v[0].([]uint8)), string(v[1].([]uint8)), bytes.NewBuffer(v[4].([]byte))) if err != nil { return nil, err } r.Header = CocaineHeaderToHttpHeader(v[3].(Headers)) r.Host = r.Header.Get("Host") if xRealIp := r.Header.Get("X-Real-IP"); xRealIp != "" { r.RemoteAddr = xRealIp } err = decompressBody(r) if err != nil { return nil, err } return r, nil }
func TestMessageUnpackErrorMsg(t *testing.T) { const ( session = 1 _type = 5 errorCode = 1 errorMessage = "someerror" ) // msgpack.packb([5, 1, [1, "someerror"]]) payload := []byte{147, 5, 1, 146, 1, 169, 115, 111, 109, 101, 101, 114, 114, 111, 114} var result []interface{} assert.NoError(t, codec.NewDecoderBytes(payload, h).Decode(&result)) msg, err := unpackMessage(result) assert.NoError(t, err) assert.Equal(t, session, msg.getSessionID(), "bad session") if !assert.Equal(t, _type, msg.getTypeID(), "bad message type") { t.FailNow() } e := msg.(*errorMsg) assert.Equal(t, errorCode, e.Code, "bad error code") assert.Equal(t, errorMessage, e.Message, "bad error message") }
func (locator *Locator) unpackchunk(chunk rawMessage) ResolveResult { var res ResolveResult err := codec.NewDecoderBytes(chunk, h).Decode(&res) if err != nil { log.Println("unpack chunk error", err) } return res }
func convertPayload(in interface{}, out interface{}) error { var buf []byte if err := codec.NewEncoderBytes(&buf, payloadHandler).Encode(in); err != nil { return err } if err := codec.NewDecoderBytes(buf, payloadHandler).Decode(out); err != nil { return err } return nil }
func BenchmarkTraceExtract(b *testing.B) { var ( //trace.pack_trace(trace.Trace(traceid=9000, spanid=11000, parentid=8000)) buff = []byte{ 147, 147, 194, 80, 168, 40, 35, 0, 0, 0, 0, 0, 0, 147, 194, 81, 168, 248, 42, 0, 0, 0, 0, 0, 0, 147, 194, 82, 168, 64, 31, 0, 0, 0, 0, 0, 0} headers CocaineHeaders ) codec.NewDecoderBytes(buff, hAsocket).MustDecode(&headers) b.ResetTimer() for n := 0; n < b.N; n++ { headers.getTraceData() } }
func TestHeaders(t *testing.T) { var ( //trace.pack_trace(trace.Trace(traceid=9000, spanid=11000, parentid=8000)) buff = []byte{ 147, 147, 194, 80, 168, 40, 35, 0, 0, 0, 0, 0, 0, 147, 194, 81, 168, 248, 42, 0, 0, 0, 0, 0, 0, 147, 194, 82, 168, 64, 31, 0, 0, 0, 0, 0, 0} headers CocaineHeaders ) codec.NewDecoderBytes(buff, hAsocket).MustDecode(&headers) assert.Equal(t, 3, len(headers)) for i, header := range headers { switch i { case 0: n, b, err := getTrace(header) assert.NoError(t, err) assert.Equal(t, uint64(traceId), n) trace, err := decodeTracingId(b) assert.NoError(t, err) assert.Equal(t, uint64(9000), trace) case 1: n, b, err := getTrace(header) assert.NoError(t, err) assert.Equal(t, uint64(spanId), n) span, err := decodeTracingId(b) assert.NoError(t, err) assert.Equal(t, uint64(11000), span) case 2: n, b, err := getTrace(header) assert.NoError(t, err) assert.Equal(t, uint64(parentId), n) parent, err := decodeTracingId(b) assert.NoError(t, err) assert.Equal(t, uint64(8000), parent) } } traceInfo, err := headers.getTraceData() assert.NoError(t, err) assert.Equal(t, uint64(9000), traceInfo.trace) assert.Equal(t, uint64(11000), traceInfo.span) assert.Equal(t, uint64(8000), traceInfo.parent) }
// UnpackProxyRequest unpacks a HTTPRequest from a serialized cocaine form func UnpackProxyRequest(raw []byte) (*http.Request, error) { var v struct { Method string URI string Version string Headers Headers Body []byte } if err := codec.NewDecoderBytes(raw, hHTTPReq).Decode(&v); err != nil { return nil, err } req, err := http.NewRequest(v.Method, v.URI, bytes.NewBuffer(v.Body)) if err != nil { return nil, err } req.Header = HeadersCocaineToHTTP(v.Headers) req.Host = req.Header.Get("Host") if xRealIP := req.Header.Get("X-Real-IP"); xRealIP != "" { req.RemoteAddr = xRealIP } // If body is compressed it will be decompressed // Inspired by https://github.com/golang/go/blob/master/src/net/http/transport.go#L883 hasBody := req != nil && req.Method != "HEAD" && req.ContentLength != 0 if hasBody && req.Header.Get("Content-Encoding") == "gzip" { req.Header.Del("Content-Encoding") req.Header.Del("Content-Length") req.ContentLength = -1 req.Body = &gzipReader{body: req.Body} } return req, nil }
func process(w http.ResponseWriter, r *http.Request) { w.Header().Add("X-Powered-By", "Cocaine") defer r.Body.Close() var ( service = r.Header.Get("X-Cocaine-Service") event = r.Header.Get("X-Cocaine-Event") ) if len(service) == 0 || len(event) == 0 { var ( j = 1 ) npos := strings.IndexByte(r.URL.Path[j:], '/') if npos < 0 { w.WriteHeader(http.StatusBadRequest) return } service = r.URL.Path[j : npos+j] j += npos + 1 npos = strings.IndexByte(r.URL.Path[j:], '/') switch npos { case -1: event = r.URL.Path[j:] r.URL.Path = "/" case 0: // EmptyEvent w.WriteHeader(http.StatusBadRequest) return default: event = r.URL.Path[j : npos+j] r.URL.Path = r.URL.Path[j+npos:] } if len(service) == 0 || len(event) == 0 { w.WriteHeader(http.StatusBadRequest) return } } ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) defer cancel() app, err := cocaine.NewService(ctx, service, nil) if err != nil { w.WriteHeader(http.StatusInternalServerError) return } defer app.Close() task, err := packRequest(r) if err != nil { w.WriteHeader(http.StatusBadRequest) return } channel, err := app.Call(ctx, "enqueue", event) if err != nil { w.WriteHeader(http.StatusBadRequest) return } if err := channel.Call(ctx, "write", task); err != nil { w.WriteHeader(http.StatusInternalServerError) return } var ( body []byte startLine struct { Code int Headers [][2]string } ) packedHeaders, err := channel.Get(ctx) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprint(w, err) return } if err := packedHeaders.ExtractTuple(&body); err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprint(w, err) return } if err := codec.NewDecoderBytes(body, hAsocket).Decode(&startLine); err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprint(w, err) return } body = body[:] log.Println(startLine) for _, header := range startLine.Headers { w.Header().Add(header[0], header[1]) } w.WriteHeader(startLine.Code) BODY: for { res, err := channel.Get(ctx) switch { case err != nil: break BODY case res.Err() != nil: break BODY case channel.Closed(): break BODY default: res.ExtractTuple(&body) w.Write(body) body = body[:] } } }
func testUnpackHTTPChunk(payload []interface{}, res interface{}) error { return codec.NewDecoderBytes(payload[0].([]byte), hHTTPReq).Decode(res) }
//Unpacks the result of the called method in the passed structure. //You can transfer the structure of a particular type that will avoid the type checking. Look at examples. func (s *serviceRes) Extract(target interface{}) (err error) { err = codec.NewDecoderBytes(s.res, h).Decode(&target) return }
func (o *Overlord) handleHTTPRequest(w http.ResponseWriter, req *http.Request) { defer req.Body.Close() w.Header().Add("X-Powered-By", "Cocaine") body, err := ioutil.ReadAll(req.Body) if err != nil { w.Header().Add("X-Error-Generated-By", "Cocaine") w.WriteHeader(http.StatusBadRequest) fmt.Fprint(w, "unable to read the whole body") return } // method uri 1.1 headers body headers := make([][2]string, 0, len(req.Header)) for header, values := range req.Header { for _, val := range values { headers = append(headers, [2]string{header, val}) } } var task []byte codec.NewEncoderBytes(&task, hAsocket).Encode([]interface{}{ req.Method, req.URL.RequestURI(), fmt.Sprintf("%d.%d", req.ProtoMajor, req.ProtoMinor), headers, body, }) channel := make(chan *cocaine.Message, 5) o.mu.Lock() o.counter++ counter := o.counter o.sessions[o.counter] = channel o.mu.Unlock() defer func() { o.mu.Lock() defer o.mu.Unlock() delete(o.sessions, counter) }() enqueueTask(counter, task, o.conn) var first = true FOR: for msg := range channel { switch msg.MsgType { case chunk: payload, ok := msg.Payload[0].([]byte) if !ok { log.Panicf("invalid response data, must be []byte") continue FOR } if first { first = false var res struct { Code int Headers [][2]string } codec.NewDecoderBytes(payload, hAsocket).Decode(&res) for _, header := range res.Headers { w.Header().Add(header[0], header[1]) } w.WriteHeader(res.Code) continue FOR } w.Write(payload) case _error: log.Println("error message from worker") w.Header().Add("X-Error-Generated-By", "Cocaine") w.WriteHeader(http.StatusInternalServerError) var msgerr struct { CodeInfo [2]int Message string } if err := convertPayload(msg.Payload, &msgerr); err != nil { fmt.Fprintf(w, "unable to decode error reply: %v", err) return } fmt.Fprintf(w, "worker replied with error: [%d] [%d] %s", msgerr.CodeInfo[0], msgerr.CodeInfo[1], msgerr.Message) return case close: // close type return default: // protocol error log.Printf("protocol error: unknown message %v", msg) } } }