Example #1
0
// 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")
}
Example #3
0
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
}
Example #4
0
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
}
Example #8
0
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)
}
Example #10
0
//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
}
Example #11
0
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)
		}
	}
}