github.com/cloudwego/hertz@v0.9.3/pkg/common/utils/chunk.go (about)

     1  /*
     2   * Copyright 2022 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package utils
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  
    24  	"github.com/cloudwego/hertz/internal/bytesconv"
    25  	"github.com/cloudwego/hertz/internal/bytestr"
    26  	"github.com/cloudwego/hertz/pkg/common/errors"
    27  	"github.com/cloudwego/hertz/pkg/network"
    28  )
    29  
    30  var errBrokenChunk = errors.NewPublic("cannot find crlf at the end of chunk")
    31  
    32  func ParseChunkSize(r network.Reader) (int, error) {
    33  	n, err := bytesconv.ReadHexInt(r)
    34  	if err != nil {
    35  		if err == io.EOF {
    36  			err = io.ErrUnexpectedEOF
    37  		}
    38  		return -1, err
    39  	}
    40  	for {
    41  		c, err := r.ReadByte()
    42  		if err != nil {
    43  			return -1, errors.NewPublic(fmt.Sprintf("cannot read '\r' char at the end of chunk size: %s", err))
    44  		}
    45  		// Skip any trailing whitespace after chunk size.
    46  		if c == ' ' {
    47  			continue
    48  		}
    49  		if c != '\r' {
    50  			return -1, errors.NewPublic(
    51  				fmt.Sprintf("unexpected char %q at the end of chunk size. Expected %q", c, '\r'),
    52  			)
    53  		}
    54  		break
    55  	}
    56  	c, err := r.ReadByte()
    57  	if err != nil {
    58  		return -1, errors.NewPublic(fmt.Sprintf("cannot read '\n' char at the end of chunk size: %s", err))
    59  	}
    60  	if c != '\n' {
    61  		return -1, errors.NewPublic(
    62  			fmt.Sprintf("unexpected char %q at the end of chunk size. Expected %q", c, '\n'),
    63  		)
    64  	}
    65  	return n, nil
    66  }
    67  
    68  // SkipCRLF will only skip the next CRLF("\r\n"), otherwise, error will be returned.
    69  func SkipCRLF(reader network.Reader) error {
    70  	p, err := reader.Peek(len(bytestr.StrCRLF))
    71  	if err != nil {
    72  		return err
    73  	}
    74  	if !bytes.Equal(p, bytestr.StrCRLF) {
    75  		return errBrokenChunk
    76  	}
    77  
    78  	reader.Skip(len(p)) // nolint: errcheck
    79  	return nil
    80  }