<commit_before>// Copyright 2013 <NAME>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package spdy2

import (
	"bytes"
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"sync"

	"github.com/SlyMarbo/spdy/common"
	"github.com/SlyMarbo/spdy/spdy2/frames"
)

// ResponseStream is a structure that implements the
// Stream interface. This is used for responding to
// client requests.
type ResponseStream struct {
	sync.Mutex

	shutdownOnce   sync.Once
	conn           *Conn
	streamID       common.StreamID
	requestBody    *bytes.Buffer
	state          *common.StreamState
	output         chan<- common.Frame
	request        *http.Request
	handler        http.Handler
	header         http.Header
	priority       common.Priority
	unidirectional bool
	responseCode   int
	ready          chan struct{}
	stop           chan bool
	wroteHeader    bool
}

func NewResponseStream(conn *Conn, frame *frames.SYN_STREAM, output chan<- common.Frame, handler http.Handler, request *http.Request) *ResponseStream {
	out := new(ResponseStream)
	out.conn = conn
	out.streamID = frame.StreamID
	out.output = output
	out.handler = handler
	if out.handler == nil {
		out.handler = http.DefaultServeMux
	}
	out.request = request
	out.priority = frame.Priority
	out.stop = conn.stop
	out.unidirectional = frame.Flags.UNIDIRECTIONAL()
	out.requestBody = new(bytes.Buffer)
	out.state = new(common.StreamState)
	out.header = make(http.Header)
	out.responseCode = 0
	out.ready = make(chan struct{})
	out.wroteHeader = false
	if frame.Flags.FIN() {
		close(out.ready)
		out.state.CloseThere()
	}
	out.request.Body = &common.ReadCloser{out.requestBody}
	return out
}

/***********************
 * http.ResponseWriter *
 ***********************/

func (s *ResponseStream) Header() http.Header {
	return s.header
}

// Write is the main method with which data is sent.
func (s *ResponseStream) Write(inputData []byte) (int, error) {
	if s.unidirectional {
		return 0, errors.New("Error: Stream is unidirectional.")
	}

	if s.closed() || s.state.ClosedHere() {
		return 0, errors.New("Error: Stream already closed.")
	}

	// Copy the data locally to avoid any pointer issues.
	data := make([]byte, len(inputData))
	copy(data, inputData)

	// Default to 200 response.
	if !s.wroteHeader {
		s.WriteHeader(http.StatusOK)
	}

	// Send any new headers.
	s.writeHeader()

	// Chunk the response if necessary.
	written := 0
	for len(data) > common.MAX_DATA_SIZE {
		dataFrame := new(frames.DATA)
		dataFrame.StreamID = s.streamID
		dataFrame.Data = data[:common.MAX_DATA_SIZE]
		s.output <- dataFrame

		written += common.MAX_DATA_SIZE
	}

	n := len(data)
	if n == 0 {
		return written, nil
	}
<commit_msg>Spdy2: Fix Infinite loop when write data of big size<commit_after>// Copyright 2013 <NAME>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package spdy2

import (
	"bytes"
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"sync"

	"github.com/SlyMarbo/spdy/common"
	"github.com/SlyMarbo/spdy/spdy2/frames"
)

// ResponseStream is a structure that implements the
// Stream interface. This is used for responding to
// client requests.
type ResponseStream struct {
	sync.Mutex

	shutdownOnce   sync.Once
	conn           *Conn
	streamID       common.StreamID
	requestBody    *bytes.Buffer
	state          *common.StreamState
	output         chan<- common.Frame
	request        *http.Request
	handler        http.Handler
	header         http.Header
	priority       common.Priority
	unidirectional bool
	responseCode   int
	ready          chan struct{}
	stop           chan bool
	wroteHeader    bool
}

func NewResponseStream(conn *Conn, frame *frames.SYN_STREAM, output chan<- common.Frame, handler http.Handler, request *http.Request) *ResponseStream {
	out := new(ResponseStream)
	out.conn = conn
	out.streamID = frame.StreamID
	out.output = output
	out.handler = handler
	if out.handler == nil {
		out.handler = http.DefaultServeMux
	}
	out.request = request
	out.priority = frame.Priority
	out.stop = conn.stop
	out.unidirectional = frame.Flags.UNIDIRECTIONAL()
	out.requestBody = new(bytes.Buffer)
	out.state = new(common.StreamState)
	out.header = make(http.Header)
	out.responseCode = 0
	out.ready = make(chan struct{})
	out.wroteHeader = false
	if frame.Flags.FIN() {
		close(out.ready)
		out.state.CloseThere()
	}
	out.request.Body = &common.ReadCloser{out.requestBody}
	return out
}

/***********************
 * http.ResponseWriter *
 ***********************/

func (s *ResponseStream) Header() http.Header {
	return s.header
}

// Write is the main method with which data is sent.
func (s *ResponseStream) Write(inputData []byte) (int, error) {
	if s.unidirectional {
		return 0, errors.New("Error: Stream is unidirectional.")
	}

	if s.closed() || s.state.ClosedHere() {
		return 0, errors.New("Error: Stream already closed.")
	}

	// Copy the data locally to avoid any pointer issues.
	data := make([]byte, len(inputData))
	copy(data, inputData)

	// Default to 200 response.
	if !s.wroteHeader {
		s.WriteHeader(http.StatusOK)
	}

	// Send any new headers.
	s.writeHeader()

	// Chunk the response if necessary.
	written := 0
	for len(data) > common.MAX_DATA_SIZE {
		dataFrame := new(frames.DATA)
		dataFrame.StreamID = s.streamID
		dataFrame.Data = data[:common.MAX_DATA_SIZE]
		s.output <- dataFrame
		
		data = data[common.MAX_DATA_SIZE:]
		written += common.MAX_DATA_SIZE
	}

	n := len(data)
	if n == 0 {
		return written, nil
	}

{'fraction_non_alphanumeric': 0.12572046109510088, 'fraction_numerical': 0.005223342939481268, 'mean_word_length': 3.3724409448818897, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6853870', 'n_tokens_mistral': 1908, 'n_tokens_neox': 1807, 'n_words': 499}