Exemple #1
0
// ReadRequest reads the data from the request into the raw.Data.
func (data *Data) ReadRequest(ctx context.Context, r *http.Request) error {
	if cl := r.Header.Get("Content-Length"); cl != "" {
		v, err := strconv.ParseInt(cl, 10, 64)
		if err != nil || v < 0 {
			return log.Warn("invalid content-length",
				log.WithValue("content-length", cl),
				log.WithContext(ctx),
				log.WithStatusBadRequest())
		}

		if v >= int64(MaxLen) {
			return log.Warn("max length excceeded",
				log.WithContext(ctx),
				log.WithStatusBadRequest(),
				log.WithValue("MaxLen", MaxLen))
		}

		buf := make([]byte, v)

		_, err = io.ReadFull(r.Body, buf)
		if err != nil {
			return log.Warn("cannot read content",
				log.WithContext(ctx),
				log.WithError(err),
				log.WithStatusBadRequest())
		}
		data.Content = buf
	} else {
		reader := io.LimitReader(r.Body, int64(MaxLen))
		content, err := ioutil.ReadAll(reader)
		if err != nil {
			return err
		}
		if len(content) >= MaxLen {
			return log.Warn("max size exceeded",
				log.WithContext(ctx),
				log.WithStatusBadRequest(),
				log.WithValue("MaxLen", MaxLen))
		}
		data.Content = content
	}

	// The HTTP specification does not mention Content-Encoding for
	// requests, but sometimes it is handy to allow the client to do
	// so.
	if ce := r.Header.Get("Content-Encoding"); ce != "" {
		data.ContentEncoding = ce
		data.UncompressedLength = 0 // not known
	} else {
		data.UncompressedLength = len(data.Content)
		data.ContentEncoding = ceIdentity
	}

	data.ContentType = r.Header.Get("Content-Type")
	if data.ContentType == "" {
		data.ContentType = "application/octet-stream"
	}
	return nil
}
func ExampleWithValue(n1, n2 int) error {
	if err := doSomethingWith(n1, n2); err != nil {
		return log.Error("doSomethingWith failed",
			log.WithValue("n1", n1),
			log.WithValue("n2", n2))
	}

	// ... more processing and then ...

	return nil
}
func ExampleOption(ctx context.Context, n1, n2 int) error {
	if err := doSomethingWith(n1, n2); err != nil {
		return log.Error("cannot doSomething",
			log.WithValue("n1", n1),
			log.WithValue("n2", n2),
			log.WithError(err),
			log.WithContext(ctx))
	}

	// .. more processing and then ...

	return nil
}
Exemple #4
0
func (data *Data) Decompress() error {
	if !data.IsCompressed() {
		return nil
	}
	input := bytes.NewBuffer(data.Content)
	var reader io.Reader
	if data.ContentEncoding == ceDeflate {
		reader = flate.NewReader(input)
	} else if data.ContentEncoding == ceGzip {
		var err error
		if reader, err = gzip.NewReader(input); err != nil {
			return err
		}
	} else {
		return log.Error("unknown content-encoding",
			log.WithValue("content-encoding", data.ContentEncoding))
	}
	writer := bytes.Buffer{}
	_, err := io.Copy(&writer, reader)
	if err != nil {
		return err
	}
	data.Content = writer.Bytes()
	data.ContentEncoding = ""
	data.UncompressedLength = len(data.Content)
	return nil
}
Exemple #5
0
// WriteResponse writes the contents to the client as a response.
func (data *Data) WriteResponse(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	// TODO: this is a very naive handling of the Accept-Encoding
	// header. In particular it does not handle deflate;q=0, which is
	// a valid way of saying that deflate is not acceptable.
	if data.IsCompressed() {
		if ae := r.Header.Get("Accept-Encoding"); !strings.Contains(ae, data.ContentEncoding) {
			// the user agent does not accept the content encoding, so we
			// have to decompress before sending
			err := data.Decompress()
			if err != nil {
				return err
			}
		}
	}

	if len(data.Content) == 0 {
		w.Header().Set("Content-Length", "0")
		w.Header().Del("Content-Type")
		w.Header().Del("Content-Encoding")
		w.WriteHeader(http.StatusNoContent)
		return nil
	}

	if data.IsCompressed() {
		w.Header().Set("Content-Encoding", data.ContentEncoding)
	} else {
		w.Header().Del("Content-Encoding")
	}
	w.Header().Set("Content-Type", data.ContentType)
	w.Header().Set("Content-Length", strconv.Itoa(len(data.Content)))
	n, err := w.Write(data.Content)
	if err != nil {
		// Failed to write, but do not return an error code, as there
		// is no way to return an error message to the client after
		// writing has started.
		log.Warn("cannot write response",
			log.WithError(err),
			log.WithContext(ctx))
	}
	if n != len(data.Content) {
		log.Warn("not all bytes sent",
			log.WithValue("expected", len(data.Content)),
			log.WithValue("actual", n),
			log.WithContext(ctx))
	}
	return nil
}