src/server/util/io.h

Sun, 04 Jun 2023 20:09:18 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 04 Jun 2023 20:09:18 +0200
changeset 498
0d80f8a2b29f
parent 430
83560f32e7d5
child 513
9a49c245a49c
permissions
-rw-r--r--

fix net_http_write when used with chunked transfer encoding and non-blocking IO

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2013 Olaf Wintermann. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef IOSTREAM_H
#define	IOSTREAM_H

#include <openssl/ssl.h> 
#include "../public/nsapi.h"
#include "systems.h"

#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#endif

#ifdef	__cplusplus
extern "C" {
#endif

#ifdef XP_UNIX
#define SYS_SOCKET int
#elif defined(XP_WIN32)
#define SYS_SOCKET SOCKET
#endif

#define IO_MODE_BLOCKING    0
#define IO_MODE_NONBLOCKING 1
    
#define IO_POLL_NONE        0
#define IO_POLL_IN          1
#define IO_POLL_OUT         2
    
typedef struct IOStream     IOStream;
typedef struct Sysstream    Sysstream;
typedef struct HttpStream   HttpStream;

typedef ssize_t(*io_write_f)(IOStream *, const void *, size_t);
typedef ssize_t(*io_writev_f)(IOStream *, struct iovec *, int);
typedef ssize_t(*io_read_f)(IOStream *, void *, size_t);
typedef ssize_t(*io_sendfile_f)(IOStream *, sendfiledata *);
typedef void(*io_close_f)(IOStream *);
typedef void(*io_finish_f)(IOStream *);
typedef void(*io_setmode_f)(IOStream *, int);
typedef int(*io_poll_f)(IOStream *, EventHandler *, int, Event *);

struct IOStream {
    io_write_f    write;
    io_writev_f   writev;
    io_read_f     read;
    io_sendfile_f sendfile;
    io_close_f    close;
    io_finish_f   finish;
    io_setmode_f  setmode;
    io_poll_f     poll;
    int           io_errno;
};

struct Sysstream {
    IOStream st;
#ifdef XP_UNIX
    int      fd;
#elif defined(XP_WIN32)
    SOCKET   fd;
#endif
};

#define HTTP_STREAM_CBUF_SIZE 16
struct HttpStream {
    IOStream st;
    IOStream *fd;
    
    uint64_t written; 
    /*
     * content-length or current chunk size
     */
    uint64_t max_read;
    /*
     * total bytes read (with content-length) or bytes read of current chunk
     */
    uint64_t read;
    /*
     * total bytes read with chunked transfer encoding
     */
    uint64_t read_total;
    /*
     * read buffer (used only with chunked transfer encoding)
     */
    char     *readbuf;
    /*
     * readbuf allocated size
     */
    size_t   bufsize;
    /*
     * number of bytes currently stored in readbuf
     */
    int      *buflen;
    /*
     * current position in the read buffer
     */
    int      *bufpos;
    /*
     * current chunk_buf position
     */
    int      chunk_buf_pos;
    /*
     * buffer used only for parsing chunk headers
     */
    char     chunk_buf[HTTP_STREAM_CBUF_SIZE];
    /*
     * chunked transfer encoding for write enabled?
     */
    WSBool   chunked_enc;
    /*
     * current chunk size (set after the header is sent)
     */
    size_t   current_chunk_length;
    /*
     * current chunk position
     */
    size_t   current_chunk_pos;
    /*
     * missing trailer before new data
     * 0: no trailer
     * 2: crlf
     * 1: lf
     */
    int      current_trailer;
    /*
     * write chunk header buffer
     */
    char     write_chunk_buf[HTTP_STREAM_CBUF_SIZE];
    /*
     * chunk header buffer length
     * only used when the chunk header was completely sent
     * must be 0 before payload data is sent
     */
    int      write_chunk_buf_len;
    /*
     * current write_chunk_buf position (if remaining != 0)
     */
    int      write_chunk_buf_pos;
    /*
     * end of file indicator (read)
     */
    WSBool   read_eof;
    /*
     * end of file indicator (write)
     */
    WSBool write_eof;
};

typedef struct SSLStream {
    IOStream st;
    SSL      *ssl;
    int      error;
} SSLStream;



/* system stream */
IOStream* Sysstream_new(pool_handle_t *pool, SYS_SOCKET fd);

ssize_t net_sys_write(Sysstream *st, const void *buf, size_t nbytes);
ssize_t net_sys_writev(Sysstream *st, struct iovec *iovec, int iovcnt);
ssize_t net_sys_read(Sysstream *st, void *buf, size_t nbytes);
ssize_t net_sys_sendfile(Sysstream *st, sendfiledata *sfd);
void net_sys_close(Sysstream *st);
void net_sys_setmode(Sysstream *st, int mode);
int net_sys_poll(Sysstream *st, EventHandler *ev, int events, Event *cb);

/* http stream */
IOStream* httpstream_new(pool_handle_t *pool, IOStream *fd);

int httpstream_enable_chunked_read(IOStream *st, char *buffer, size_t bufsize, int *cursize, int *pos);
int httpstream_enable_chunked_write(IOStream *st);
int httpstream_set_max_read(IOStream *st, int64_t maxread);
WSBool httpstream_eof(IOStream *st);
int64_t httpstream_written(IOStream *st);

ssize_t net_http_write(HttpStream *st, const void *buf, size_t nbytes);
ssize_t net_http_writev(HttpStream *st, struct iovec *iovec, int iovcnt);
ssize_t net_http_read(HttpStream *st, void *buf, size_t nbytes);
ssize_t net_http_read_chunked(HttpStream *st, void *buf, size_t nbytes);
ssize_t net_http_sendfile(HttpStream *st, sendfiledata *sfd);
void    net_http_close(HttpStream *st);
void    net_http_finish(HttpStream *st);
void    net_http_setmode(HttpStream *st, int mode);
int     net_http_poll(HttpStream *st, EventHandler *ev, int events, Event *cb);

int http_stream_parse_chunk_header(char *str, int len, WSBool first, int64_t *chunklen);

/* ssl stream */
IOStream* sslstream_new(pool_handle_t *pool, SSL *ssl);

ssize_t net_ssl_write(SSLStream *st, const void *buf, size_t nbytes);
ssize_t net_ssl_writev(SSLStream *st, struct iovec *iovec, int iovcnt);
ssize_t net_ssl_read(SSLStream *st, void *buf, size_t nbytes);
void    net_ssl_close(SSLStream *st);
void    net_ssl_finish(SSLStream *st);
void    net_ssl_setmode(SSLStream *st, int mode);
int     net_ssl_poll(SSLStream *st, EventHandler *ev, int events, Event *cb);

/* net_ functions */
ssize_t net_fallback_sendfile(IOStream *fd, sendfiledata *sfd);
void    net_finish(SYS_NETFD fd);

#ifdef	__cplusplus
}
#endif

#endif	/* IOSTREAM_H */

mercurial