<commit_before>//! This module implements a minimal and non standard conforming HTTP 1.0
//! round-tripper that works with the bitcoind RPC server. This can be used
//! if minimal dependencies are a goal and synchronous communication is ok.

use std::{fmt, io, net, thread};
use std::io::{BufRead, BufReader, Write};
use std::net::{ToSocketAddrs, TcpStream};
use std::time::{Instant, Duration};

use base64;
use serde;
use serde_json;

use ::client::Transport;
use ::{Request, Response};

/// The default TCP port to use for connections.
/// Set to 8332, the default RPC port for bitcoind.
pub const DEFAULT_PORT: u16 = 8332;

/// Simple HTTP transport that implements the necessary subset of HTTP for
/// running a bitcoind RPC client.
#[derive(Clone, Debug)]
pub struct SimpleHttpTransport {
    addr: net::SocketAddr,
    path: String,
    timeout: Duration,
    /// The value of the `Authorization` HTTP header.
    basic_auth: Option<String>,
}

impl Default for SimpleHttpTransport {
    fn default() -> Self {
        SimpleHttpTransport {
            addr: net::SocketAddr::new(net::IpAddr::V4(net::Ipv4Addr::new(127, 0, 0, 1)), DEFAULT_PORT),
            path: "/".to_owned(),
            timeout: Duration::from_secs(15),
            basic_auth: None,
        }
    }
}

impl SimpleHttpTransport {
    /// Construct a new `SimpleHttpTransport` with default parameters
    pub fn new() -> Self {
        SimpleHttpTransport::default()
    }

    /// Returns a builder for `SimpleHttpTransport`
    pub fn builder() -> Builder {
        Builder::new()
    }

    fn request<R>(&self, req: impl serde::Serialize) -> Result<R, Error>
        where R: for<'a> serde::de::Deserialize<'a>
    {
        // Open connection
        let request_deadline = Instant::now() + self.timeout;
        let mut sock = TcpStream::connect_timeout(&self.addr, self.timeout)?;

        sock.set_read_timeout(Some(self.timeout))?;
        sock.set_write_timeout(Some(self.timeout))?;

        // Serialize the body first so we can set the Content-Length header.
        let body = serde_json::to_vec(&req)?;

        // Send HTTP request
        sock.write_all(b"POST ")?;
        sock.write_all(self.path.as_bytes())?;
        sock.write_all(b" HTTP/1.1\r\n")?;
        // Write headers
        sock.write_all(b"Connection: Close\r\n")?;
        sock.write_all(b"Content-Type: application/json\r\n")?;
        sock.write_all(b"Content-Length: ")?;
        sock.write_all(body.len().to_string().as_bytes())?;
        sock.write_all(b"\r\n")?;
        if let Some(ref auth) = self.basic_auth {
            sock.write_all(b"Authorization: ")?;
            sock.write_all(auth.as_ref())?;
            sock.write_all(b"\r\n")?;
        }
        // Write body
        sock.write_all(b"\r\n")?;
        sock.write_all(&body)?;
        sock.flush()?;

        // Receive response
        let mut reader = BufReader::new(sock);

        // Parse first HTTP response header line
        let http_response = get_line(&mut reader, request_deadline)?;
        if http_response.len() < 12 || !http_response.starts_with("HTTP/1.1 ") {
            return Err(Error::HttpParseError);
        }
        let response_code = match http_response[9..12].parse::<u16>() {
            Ok(n) => n,
            Err(_) => return Err(Error::HttpParseError),
        };

        // Skip response header fields
        while get_line(&mut reader, request_deadline)? != "\r\n" {}

        // Even if it's != 200, we parse the response as we may get a JSONRPC error instead
        // of the less meaningful HTTP error code.
        let resp_body = get_line(&mut reader, request_deadline)?;
        match serde_json::from_str(&resp_body) {
            Ok(s) => Ok(s),
            Err(e) => {
                if response_code != 200 {
                    Err(Error::HttpErrorCode(response_code))
                } else {
                    // If it was 200 then probably it was legitimately a parse error
                    Err(e.into())
                }
            }
        }
    }
}

/// Error that can happen when sending requests
#[derive(Debug)]
pub enum Error {<commit_msg>Don't attempt to read a body for auth error (401)<commit_after>//! This module implements a minimal and non standard conforming HTTP 1.0
//! round-tripper that works with the bitcoind RPC server. This can be used
//! if minimal dependencies are a goal and synchronous communication is ok.

use std::{fmt, io, net, thread};
use std::io::{BufRead, BufReader, Write};
use std::net::{ToSocketAddrs, TcpStream};
use std::time::{Instant, Duration};

use base64;
use serde;
use serde_json;

use ::client::Transport;
use ::{Request, Response};

/// The default TCP port to use for connections.
/// Set to 8332, the default RPC port for bitcoind.
pub const DEFAULT_PORT: u16 = 8332;

/// Simple HTTP transport that implements the necessary subset of HTTP for
/// running a bitcoind RPC client.
#[derive(Clone, Debug)]
pub struct SimpleHttpTransport {
    addr: net::SocketAddr,
    path: String,
    timeout: Duration,
    /// The value of the `Authorization` HTTP header.
    basic_auth: Option<String>,
}

impl Default for SimpleHttpTransport {
    fn default() -> Self {
        SimpleHttpTransport {
            addr: net::SocketAddr::new(net::IpAddr::V4(net::Ipv4Addr::new(127, 0, 0, 1)), DEFAULT_PORT),
            path: "/".to_owned(),
            timeout: Duration::from_secs(15),
            basic_auth: None,
        }
    }
}

impl SimpleHttpTransport {
    /// Construct a new `SimpleHttpTransport` with default parameters
    pub fn new() -> Self {
        SimpleHttpTransport::default()
    }

    /// Returns a builder for `SimpleHttpTransport`
    pub fn builder() -> Builder {
        Builder::new()
    }

    fn request<R>(&self, req: impl serde::Serialize) -> Result<R, Error>
        where R: for<'a> serde::de::Deserialize<'a>
    {
        // Open connection
        let request_deadline = Instant::now() + self.timeout;
        let mut sock = TcpStream::connect_timeout(&self.addr, self.timeout)?;

        sock.set_read_timeout(Some(self.timeout))?;
        sock.set_write_timeout(Some(self.timeout))?;

        // Serialize the body first so we can set the Content-Length header.
        let body = serde_json::to_vec(&req)?;

        // Send HTTP request
        sock.write_all(b"POST ")?;
        sock.write_all(self.path.as_bytes())?;
        sock.write_all(b" HTTP/1.1\r\n")?;
        // Write headers
        sock.write_all(b"Connection: Close\r\n")?;
        sock.write_all(b"Content-Type: application/json\r\n")?;
        sock.write_all(b"Content-Length: ")?;
        sock.write_all(body.len().to_string().as_bytes())?;
        sock.write_all(b"\r\n")?;
        if let Some(ref auth) = self.basic_auth {
            sock.write_all(b"Authorization: ")?;
            sock.write_all(auth.as_ref())?;
            sock.write_all(b"\r\n")?;
        }
        // Write body
        sock.write_all(b"\r\n")?;
        sock.write_all(&body)?;
        sock.flush()?;

        // Receive response
        let mut reader = BufReader::new(sock);

        // Parse first HTTP response header line
        let http_response = get_line(&mut reader, request_deadline)?;
        if http_response.len() < 12 || !http_response.starts_with("HTTP/1.1 ") {
            return Err(Error::HttpParseError);
        }
        let response_code = match http_response[9..12].parse::<u16>() {
            Ok(n) => n,
            Err(_) => return Err(Error::HttpParseError),
        };

        // Skip response header fields
        while get_line(&mut reader, request_deadline)? != "\r\n" {}

        if response_code == 401 {
            // There is no body in a 401 response, so don't try to read it
            return Err(Error::HttpErrorCode(response_code));
        }

        // Even if it's != 200, we parse the response as we may get a JSONRPC error instead
        // of the less meaningful HTTP error code.
        let resp_body = get_line(&mut reader, request_deadline)?;
        match serde_json::from_str(&resp_body) {
            Ok(s) => Ok(s),
            Err(e) => {
                if response_code != 200 {
                    Err(Error::HttpErrorCode(response_code))
                } else {
                    // If it was 200 then probably it was legitimately a parse error
                    Err(e.into())
                }
            }
        }
    }
}

/// Error that can happen when sending requests
#[derive(Debug)]
pub enum Error {
{'fraction_non_alphanumeric': 0.1315758503001059, 'fraction_numerical': 0.011415793809579852, 'mean_word_length': 2.3642121931908155, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 31, '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': '1311773', 'n_tokens_mistral': 2587, 'n_tokens_neox': 2533, 'n_words': 694}