CARPLAY版本整理
This commit is contained in:
584
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/altcp_proxyconnect.c
Normal file
584
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/altcp_proxyconnect.c
Normal file
@ -0,0 +1,584 @@
|
||||
/**
|
||||
* @file
|
||||
* Application layered TCP connection API that executes a proxy-connect.
|
||||
*
|
||||
* This file provides a starting layer that executes a proxy-connect e.g. to
|
||||
* set up TLS connections through a http proxy.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Simon Goldschmidt
|
||||
* 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt <goldsimon@gmx.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/apps/altcp_proxyconnect.h"
|
||||
|
||||
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/altcp.h"
|
||||
#include "lwip/priv/altcp_priv.h"
|
||||
|
||||
#include "lwip/altcp_tcp.h"
|
||||
#include "lwip/altcp_tls.h"
|
||||
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/init.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/** This string is passed in the HTTP header as "User-Agent: " */
|
||||
#ifndef ALTCP_PROXYCONNECT_CLIENT_AGENT
|
||||
#define ALTCP_PROXYCONNECT_CLIENT_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)"
|
||||
#endif
|
||||
|
||||
#define ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED 0x01
|
||||
#define ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE 0x02
|
||||
|
||||
typedef struct altcp_proxyconnect_state_s
|
||||
{
|
||||
ip_addr_t outer_addr;
|
||||
u16_t outer_port;
|
||||
struct altcp_proxyconnect_config *conf;
|
||||
u8_t flags;
|
||||
} altcp_proxyconnect_state_t;
|
||||
|
||||
/* Variable prototype, the actual declaration is at the end of this file
|
||||
since it contains pointers to static functions declared here */
|
||||
extern const struct altcp_functions altcp_proxyconnect_functions;
|
||||
|
||||
/* memory management functions: */
|
||||
|
||||
static altcp_proxyconnect_state_t *
|
||||
altcp_proxyconnect_state_alloc(void)
|
||||
{
|
||||
altcp_proxyconnect_state_t *ret = (altcp_proxyconnect_state_t *)mem_calloc(1, sizeof(altcp_proxyconnect_state_t));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_state_free(altcp_proxyconnect_state_t *state)
|
||||
{
|
||||
LWIP_ASSERT("state != NULL", state != NULL);
|
||||
mem_free(state);
|
||||
}
|
||||
|
||||
/* helper functions */
|
||||
|
||||
#define PROXY_CONNECT "CONNECT %s:%d HTTP/1.1\r\n" /* HOST, PORT */ \
|
||||
"User-Agent: %s\r\n" /* User-Agent */\
|
||||
"Proxy-Connection: keep-alive\r\n" \
|
||||
"Connection: keep-alive\r\n" \
|
||||
"\r\n"
|
||||
#define PROXY_CONNECT_FORMAT(host, port) PROXY_CONNECT, host, port, ALTCP_PROXYCONNECT_CLIENT_AGENT
|
||||
|
||||
/* Format the http proxy connect request via snprintf */
|
||||
static int
|
||||
altcp_proxyconnect_format_request(char *buffer, size_t bufsize, const char *host, int port)
|
||||
{
|
||||
return snprintf(buffer, bufsize, PROXY_CONNECT_FORMAT(host, port));
|
||||
}
|
||||
|
||||
/* Create and send the http proxy connect request */
|
||||
static err_t
|
||||
altcp_proxyconnect_send_request(struct altcp_pcb *conn)
|
||||
{
|
||||
int len, len2;
|
||||
mem_size_t alloc_len;
|
||||
char *buffer, *host;
|
||||
altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
|
||||
if (!state) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
/* Use printf with zero length to get the required allocation size */
|
||||
len = altcp_proxyconnect_format_request(NULL, 0, "", state->outer_port);
|
||||
if (len < 0) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
/* add allocation size for IP address strings */
|
||||
#if LWIP_IPV6
|
||||
len += 40; /* worst-case IPv6 address length */
|
||||
#else
|
||||
len += 16; /* worst-case IPv4 address length */
|
||||
#endif
|
||||
alloc_len = (mem_size_t)len;
|
||||
if ((len < 0) || (int)alloc_len != len) {
|
||||
/* overflow */
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* Allocate a bufer for the request string */
|
||||
buffer = (char *)mem_malloc(alloc_len);
|
||||
if (buffer == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
host = ipaddr_ntoa(&state->outer_addr);
|
||||
len2 = altcp_proxyconnect_format_request(buffer, alloc_len, host, state->outer_port);
|
||||
if ((len2 > 0) && (len2 <= len) && (len2 <= 0xFFFF)) {
|
||||
err_t err = altcp_write(conn->inner_conn, buffer, (u16_t)len2, TCP_WRITE_FLAG_COPY);
|
||||
if (err != ERR_OK) {
|
||||
/* @todo: abort? */
|
||||
mem_free(buffer);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
mem_free(buffer);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* callback functions from inner/lower connection: */
|
||||
|
||||
/** Connected callback from lower connection (i.e. TCP).
|
||||
* Not really implemented/tested yet...
|
||||
*/
|
||||
static err_t
|
||||
altcp_proxyconnect_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
if (conn && conn->state) {
|
||||
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
|
||||
LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
|
||||
/* upper connected is called when handshake is done */
|
||||
if (err != ERR_OK) {
|
||||
if (conn->connected) {
|
||||
if (conn->connected(conn->arg, conn, err) == ERR_ABRT) {
|
||||
return ERR_ABRT;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
/* send proxy connect request here */
|
||||
return altcp_proxyconnect_send_request(conn);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/** Recv callback from lower connection (i.e. TCP)
|
||||
* This one mainly differs between connection setup (wait for proxy OK string)
|
||||
* and application phase (data is passed on to the application).
|
||||
*/
|
||||
static err_t
|
||||
altcp_proxyconnect_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err)
|
||||
{
|
||||
altcp_proxyconnect_state_t *state;
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
|
||||
LWIP_ASSERT("no err expected", err == ERR_OK);
|
||||
LWIP_UNUSED_ARG(err);
|
||||
|
||||
if (!conn) {
|
||||
/* no connection given as arg? should not happen, but prevent pbuf/conn leaks */
|
||||
if (p != NULL) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
altcp_close(inner_conn);
|
||||
return ERR_CLSD;
|
||||
}
|
||||
state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
|
||||
if (!state) {
|
||||
/* already closed */
|
||||
if (p != NULL) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
altcp_close(inner_conn);
|
||||
return ERR_CLSD;
|
||||
}
|
||||
if (state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE) {
|
||||
/* application phase, just pass this through */
|
||||
if (conn->recv) {
|
||||
return conn->recv(conn->arg, conn, p, err);
|
||||
}
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
} else {
|
||||
/* setup phase */
|
||||
/* handle NULL pbuf (inner connection closed) */
|
||||
if (p == NULL) {
|
||||
if (altcp_close(conn) != ERR_OK) {
|
||||
altcp_abort(conn);
|
||||
return ERR_ABRT;
|
||||
}
|
||||
return ERR_OK;
|
||||
} else {
|
||||
/* @todo: parse setup phase rx data
|
||||
for now, we just wait for the end of the header... */
|
||||
u16_t idx = pbuf_memfind(p, "\r\n\r\n", 4, 0);
|
||||
altcp_recved(inner_conn, p->tot_len);
|
||||
pbuf_free(p);
|
||||
if (idx != 0xFFFF) {
|
||||
state->flags |= ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE;
|
||||
if (conn->connected) {
|
||||
return conn->connected(conn->arg, conn, ERR_OK);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Sent callback from lower connection (i.e. TCP)
|
||||
* This only informs the upper layer to try to send more, not about
|
||||
* the number of ACKed bytes.
|
||||
*/
|
||||
static err_t
|
||||
altcp_proxyconnect_lower_sent(void *arg, struct altcp_pcb *inner_conn, u16_t len)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
LWIP_UNUSED_ARG(len);
|
||||
if (conn) {
|
||||
altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
|
||||
LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
|
||||
if (!state || !(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
|
||||
/* @todo: do something here? */
|
||||
return ERR_OK;
|
||||
}
|
||||
/* pass this on to upper sent */
|
||||
if (conn->sent) {
|
||||
return conn->sent(conn->arg, conn, len);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Poll callback from lower connection (i.e. TCP)
|
||||
* Just pass this on to the application.
|
||||
* @todo: retry sending?
|
||||
*/
|
||||
static err_t
|
||||
altcp_proxyconnect_lower_poll(void *arg, struct altcp_pcb *inner_conn)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
if (conn) {
|
||||
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
|
||||
LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
|
||||
if (conn->poll) {
|
||||
return conn->poll(conn->arg, conn);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_lower_err(void *arg, err_t err)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
if (conn) {
|
||||
conn->inner_conn = NULL; /* already freed */
|
||||
if (conn->err) {
|
||||
conn->err(conn->arg, err);
|
||||
}
|
||||
altcp_free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* setup functions */
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_setup_callbacks(struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
|
||||
{
|
||||
altcp_arg(inner_conn, conn);
|
||||
altcp_recv(inner_conn, altcp_proxyconnect_lower_recv);
|
||||
altcp_sent(inner_conn, altcp_proxyconnect_lower_sent);
|
||||
altcp_err(inner_conn, altcp_proxyconnect_lower_err);
|
||||
/* tcp_poll is set when interval is set by application */
|
||||
/* listen is set totally different :-) */
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_proxyconnect_setup(struct altcp_proxyconnect_config *config, struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
|
||||
{
|
||||
altcp_proxyconnect_state_t *state;
|
||||
if (!config) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
LWIP_ASSERT("invalid inner_conn", conn != inner_conn);
|
||||
|
||||
/* allocate proxyconnect context */
|
||||
state = altcp_proxyconnect_state_alloc();
|
||||
if (state == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
state->flags = 0;
|
||||
state->conf = config;
|
||||
altcp_proxyconnect_setup_callbacks(conn, inner_conn);
|
||||
conn->inner_conn = inner_conn;
|
||||
conn->fns = &altcp_proxyconnect_functions;
|
||||
conn->state = state;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Allocate a new altcp layer connecting through a proxy.
|
||||
* This function gets the inner pcb passed.
|
||||
*
|
||||
* @param config struct altcp_proxyconnect_config that contains the proxy settings
|
||||
* @param inner_pcb pcb that makes the connection to the proxy (i.e. tcp pcb)
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_proxyconnect_new(struct altcp_proxyconnect_config *config, struct altcp_pcb *inner_pcb)
|
||||
{
|
||||
struct altcp_pcb *ret;
|
||||
if (inner_pcb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret = altcp_alloc();
|
||||
if (ret != NULL) {
|
||||
if (altcp_proxyconnect_setup(config, ret, inner_pcb) != ERR_OK) {
|
||||
altcp_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Allocate a new altcp layer connecting through a proxy.
|
||||
* This function allocates the inner pcb as tcp pcb, resulting in a direct tcp
|
||||
* connection to the proxy.
|
||||
*
|
||||
* @param config struct altcp_proxyconnect_config that contains the proxy settings
|
||||
* @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_proxyconnect_new_tcp(struct altcp_proxyconnect_config *config, u8_t ip_type)
|
||||
{
|
||||
struct altcp_pcb *inner_pcb, *ret;
|
||||
|
||||
/* inner pcb is tcp */
|
||||
inner_pcb = altcp_tcp_new_ip_type(ip_type);
|
||||
if (inner_pcb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret = altcp_proxyconnect_new(config, inner_pcb);
|
||||
if (ret == NULL) {
|
||||
altcp_close(inner_pcb);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Allocator function to allocate a proxy connect altcp pcb connecting directly
|
||||
* via tcp to the proxy.
|
||||
*
|
||||
* The returned pcb is a chain: altcp_proxyconnect - altcp_tcp - tcp pcb
|
||||
*
|
||||
* This function is meant for use with @ref altcp_new.
|
||||
*
|
||||
* @param arg struct altcp_proxyconnect_config that contains the proxy settings
|
||||
* @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_proxyconnect_alloc(void *arg, u8_t ip_type)
|
||||
{
|
||||
return altcp_proxyconnect_new_tcp((struct altcp_proxyconnect_config *)arg, ip_type);
|
||||
}
|
||||
|
||||
|
||||
#if LWIP_ALTCP_TLS
|
||||
|
||||
/** Allocator function to allocate a TLS connection through a proxy.
|
||||
*
|
||||
* The returned pcb is a chain: altcp_tls - altcp_proxyconnect - altcp_tcp - tcp pcb
|
||||
*
|
||||
* This function is meant for use with @ref altcp_new.
|
||||
*
|
||||
* @param arg struct altcp_proxyconnect_tls_config that contains the proxy settings
|
||||
* and tls settings
|
||||
* @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_proxyconnect_tls_alloc(void *arg, u8_t ip_type)
|
||||
{
|
||||
struct altcp_proxyconnect_tls_config *cfg = (struct altcp_proxyconnect_tls_config *)arg;
|
||||
struct altcp_pcb *proxy_pcb;
|
||||
struct altcp_pcb *tls_pcb;
|
||||
|
||||
proxy_pcb = altcp_proxyconnect_new_tcp(&cfg->proxy, ip_type);
|
||||
tls_pcb = altcp_tls_wrap(cfg->tls_config, proxy_pcb);
|
||||
|
||||
if (tls_pcb == NULL) {
|
||||
altcp_close(proxy_pcb);
|
||||
}
|
||||
return tls_pcb;
|
||||
}
|
||||
#endif /* LWIP_ALTCP_TLS */
|
||||
|
||||
/* "virtual" functions */
|
||||
static void
|
||||
altcp_proxyconnect_set_poll(struct altcp_pcb *conn, u8_t interval)
|
||||
{
|
||||
if (conn != NULL) {
|
||||
altcp_poll(conn->inner_conn, altcp_proxyconnect_lower_poll, interval);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_recved(struct altcp_pcb *conn, u16_t len)
|
||||
{
|
||||
altcp_proxyconnect_state_t *state;
|
||||
if (conn == NULL) {
|
||||
return;
|
||||
}
|
||||
state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
if (state == NULL) {
|
||||
return;
|
||||
}
|
||||
if (!(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
|
||||
return;
|
||||
}
|
||||
altcp_recved(conn->inner_conn, len);
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_proxyconnect_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
|
||||
{
|
||||
altcp_proxyconnect_state_t *state;
|
||||
|
||||
if ((conn == NULL) || (ipaddr == NULL)) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
if (state == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
if (state->flags & ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
state->flags |= ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED;
|
||||
|
||||
conn->connected = connected;
|
||||
/* connect to our proxy instead, but store the requested address and port */
|
||||
ip_addr_copy(state->outer_addr, *ipaddr);
|
||||
state->outer_port = port;
|
||||
|
||||
return altcp_connect(conn->inner_conn, &state->conf->proxy_addr, state->conf->proxy_port, altcp_proxyconnect_lower_connected);
|
||||
}
|
||||
|
||||
static struct altcp_pcb *
|
||||
altcp_proxyconnect_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err)
|
||||
{
|
||||
LWIP_UNUSED_ARG(conn);
|
||||
LWIP_UNUSED_ARG(backlog);
|
||||
LWIP_UNUSED_ARG(err);
|
||||
/* listen not supported! */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_abort(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn != NULL) {
|
||||
if (conn->inner_conn != NULL) {
|
||||
altcp_abort(conn->inner_conn);
|
||||
}
|
||||
altcp_free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_proxyconnect_close(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
if (conn->inner_conn != NULL) {
|
||||
err_t err = altcp_close(conn->inner_conn);
|
||||
if (err != ERR_OK) {
|
||||
/* closing inner conn failed, return the error */
|
||||
return err;
|
||||
}
|
||||
}
|
||||
/* no inner conn or closing it succeeded, deallocate myself */
|
||||
altcp_free(conn);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_proxyconnect_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
|
||||
{
|
||||
altcp_proxyconnect_state_t *state;
|
||||
|
||||
LWIP_UNUSED_ARG(apiflags);
|
||||
|
||||
if (conn == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
if (state == NULL) {
|
||||
/* @todo: which error? */
|
||||
return ERR_CLSD;
|
||||
}
|
||||
if (!(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
|
||||
/* @todo: which error? */
|
||||
return ERR_VAL;
|
||||
}
|
||||
return altcp_write(conn->inner_conn, dataptr, len, apiflags);
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_dealloc(struct altcp_pcb *conn)
|
||||
{
|
||||
/* clean up and free tls state */
|
||||
if (conn) {
|
||||
altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
if (state) {
|
||||
altcp_proxyconnect_state_free(state);
|
||||
conn->state = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
const struct altcp_functions altcp_proxyconnect_functions = {
|
||||
altcp_proxyconnect_set_poll,
|
||||
altcp_proxyconnect_recved,
|
||||
altcp_default_bind,
|
||||
altcp_proxyconnect_connect,
|
||||
altcp_proxyconnect_listen,
|
||||
altcp_proxyconnect_abort,
|
||||
altcp_proxyconnect_close,
|
||||
altcp_default_shutdown,
|
||||
altcp_proxyconnect_write,
|
||||
altcp_default_output,
|
||||
altcp_default_mss,
|
||||
altcp_default_sndbuf,
|
||||
altcp_default_sndqueuelen,
|
||||
altcp_default_nagle_disable,
|
||||
altcp_default_nagle_enable,
|
||||
altcp_default_nagle_disabled,
|
||||
altcp_default_setprio,
|
||||
altcp_proxyconnect_dealloc,
|
||||
altcp_default_get_tcp_addrinfo,
|
||||
altcp_default_get_ip,
|
||||
altcp_default_get_port
|
||||
#ifdef LWIP_DEBUG
|
||||
, altcp_default_dbg_get_tcp_state
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* LWIP_ALTCP */
|
174
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fs.c
Normal file
174
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fs.c
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/apps/httpd_opts.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/apps/fs.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include HTTPD_FSDATA_FILE
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
#if LWIP_HTTPD_CUSTOM_FILES
|
||||
int fs_open_custom(struct fs_file *file, const char *name);
|
||||
void fs_close_custom(struct fs_file *file);
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
u8_t fs_canread_custom(struct fs_file *file);
|
||||
u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg);
|
||||
int fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg);
|
||||
#else /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
int fs_read_custom(struct fs_file *file, char *buffer, int count);
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
#endif /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
fs_open(struct fs_file *file, const char *name)
|
||||
{
|
||||
const struct fsdata_file *f;
|
||||
|
||||
if ((file == NULL) || (name == NULL)) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
#if LWIP_HTTPD_CUSTOM_FILES
|
||||
if (fs_open_custom(file, name)) {
|
||||
file->is_custom_file = 1;
|
||||
return ERR_OK;
|
||||
}
|
||||
file->is_custom_file = 0;
|
||||
#endif /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
|
||||
for (f = FS_ROOT; f != NULL; f = f->next) {
|
||||
if (!strcmp(name, (const char *)f->name)) {
|
||||
file->data = (const char *)f->data;
|
||||
file->len = f->len;
|
||||
file->index = f->len;
|
||||
file->pextension = NULL;
|
||||
file->flags = f->flags;
|
||||
#if HTTPD_PRECALCULATED_CHECKSUM
|
||||
file->chksum_count = f->chksum_count;
|
||||
file->chksum = f->chksum;
|
||||
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
|
||||
#if LWIP_HTTPD_FILE_STATE
|
||||
file->state = fs_state_init(file, name);
|
||||
#endif /* #if LWIP_HTTPD_FILE_STATE */
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
/* file not found */
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
fs_close(struct fs_file *file)
|
||||
{
|
||||
#if LWIP_HTTPD_CUSTOM_FILES
|
||||
if (file->is_custom_file) {
|
||||
fs_close_custom(file);
|
||||
}
|
||||
#endif /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
#if LWIP_HTTPD_FILE_STATE
|
||||
fs_state_free(file, file->state);
|
||||
#endif /* #if LWIP_HTTPD_FILE_STATE */
|
||||
LWIP_UNUSED_ARG(file);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if LWIP_HTTPD_DYNAMIC_FILE_READ
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
int
|
||||
fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg)
|
||||
#else /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
int
|
||||
fs_read(struct fs_file *file, char *buffer, int count)
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
{
|
||||
int read;
|
||||
if (file->index == file->len) {
|
||||
return FS_READ_EOF;
|
||||
}
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
LWIP_UNUSED_ARG(callback_fn);
|
||||
LWIP_UNUSED_ARG(callback_arg);
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
#if LWIP_HTTPD_CUSTOM_FILES
|
||||
if (file->is_custom_file) {
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
return fs_read_async_custom(file, buffer, count, callback_fn, callback_arg);
|
||||
#else /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
return fs_read_custom(file, buffer, count);
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
}
|
||||
#endif /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
|
||||
read = file->len - file->index;
|
||||
if (read > count) {
|
||||
read = count;
|
||||
}
|
||||
|
||||
MEMCPY(buffer, (file->data + file->index), read);
|
||||
file->index += read;
|
||||
|
||||
return (read);
|
||||
}
|
||||
#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
int
|
||||
fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg)
|
||||
{
|
||||
if (file != NULL) {
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
#if LWIP_HTTPD_CUSTOM_FILES
|
||||
if (!fs_canread_custom(file)) {
|
||||
if (fs_wait_read_custom(file, callback_fn, callback_arg)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
LWIP_UNUSED_ARG(callback_fn);
|
||||
LWIP_UNUSED_ARG(callback_arg);
|
||||
#endif /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
int
|
||||
fs_bytes_left(struct fs_file *file)
|
||||
{
|
||||
return file->len - file->index;
|
||||
}
|
21
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fs/404.html
Normal file
21
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fs/404.html
Normal file
@ -0,0 +1,21 @@
|
||||
<html>
|
||||
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
|
||||
<body bgcolor="white" text="black">
|
||||
|
||||
<table width="100%">
|
||||
<tr valign="top"><td width="80">
|
||||
<a href="http://www.sics.se/"><img src="/img/sics.gif"
|
||||
border="0" alt="SICS logo" title="SICS logo"></a>
|
||||
</td><td width="500">
|
||||
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
|
||||
<h2>404 - Page not found</h2>
|
||||
<p>
|
||||
Sorry, the page you are requesting was not found on this
|
||||
server.
|
||||
</p>
|
||||
</td><td>
|
||||
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
BIN
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fs/img/sics.gif
Normal file
BIN
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fs/img/sics.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 724 B |
47
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fs/index.html
Normal file
47
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fs/index.html
Normal file
@ -0,0 +1,47 @@
|
||||
<html>
|
||||
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
|
||||
<body bgcolor="white" text="black">
|
||||
|
||||
<table width="100%">
|
||||
<tr valign="top"><td width="80">
|
||||
<a href="http://www.sics.se/"><img src="/img/sics.gif"
|
||||
border="0" alt="SICS logo" title="SICS logo"></a>
|
||||
</td><td width="500">
|
||||
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
|
||||
<p>
|
||||
The web page you are watching was served by a simple web
|
||||
server running on top of the lightweight TCP/IP stack <a
|
||||
href="http://www.sics.se/~adam/lwip/">lwIP</a>.
|
||||
</p>
|
||||
<p>
|
||||
lwIP is an open source implementation of the TCP/IP
|
||||
protocol suite that was originally written by <a
|
||||
href="http://www.sics.se/~adam/lwip/">Adam Dunkels
|
||||
of the Swedish Institute of Computer Science</a> but now is
|
||||
being actively developed by a team of developers
|
||||
distributed world-wide. Since it's release, lwIP has
|
||||
spurred a lot of interest and has been ported to several
|
||||
platforms and operating systems. lwIP can be used either
|
||||
with or without an underlying OS.
|
||||
</p>
|
||||
<p>
|
||||
The focus of the lwIP TCP/IP implementation is to reduce
|
||||
the RAM usage while still having a full scale TCP. This
|
||||
makes lwIP suitable for use in embedded systems with tens
|
||||
of kilobytes of free RAM and room for around 40 kilobytes
|
||||
of code ROM.
|
||||
</p>
|
||||
<p>
|
||||
More information about lwIP can be found at the lwIP
|
||||
homepage at <a
|
||||
href="http://savannah.nongnu.org/projects/lwip/">http://savannah.nongnu.org/projects/lwip/</a>
|
||||
or at the lwIP wiki at <a
|
||||
href="http://lwip.wikia.com/">http://lwip.wikia.com/</a>.
|
||||
</p>
|
||||
</td><td>
|
||||
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
337
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fsdata.c
Normal file
337
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fsdata.c
Normal file
@ -0,0 +1,337 @@
|
||||
#include "lwip/apps/fs.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
|
||||
#define file_NULL (struct fsdata_file *) NULL
|
||||
|
||||
|
||||
#ifndef FS_FILE_FLAGS_HEADER_INCLUDED
|
||||
#define FS_FILE_FLAGS_HEADER_INCLUDED 1
|
||||
#endif
|
||||
#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT
|
||||
#define FS_FILE_FLAGS_HEADER_PERSISTENT 0
|
||||
#endif
|
||||
/* FSDATA_FILE_ALIGNMENT: 0=off, 1=by variable, 2=by include */
|
||||
#ifndef FSDATA_FILE_ALIGNMENT
|
||||
#define FSDATA_FILE_ALIGNMENT 0
|
||||
#endif
|
||||
#ifndef FSDATA_ALIGN_PRE
|
||||
#define FSDATA_ALIGN_PRE
|
||||
#endif
|
||||
#ifndef FSDATA_ALIGN_POST
|
||||
#define FSDATA_ALIGN_POST
|
||||
#endif
|
||||
#if FSDATA_FILE_ALIGNMENT==2
|
||||
#include "fsdata_alignment.h"
|
||||
#endif
|
||||
#if FSDATA_FILE_ALIGNMENT==1
|
||||
static const unsigned int dummy_align__img_sics_gif = 0;
|
||||
#endif
|
||||
static const unsigned char FSDATA_ALIGN_PRE data__img_sics_gif[] FSDATA_ALIGN_POST = {
|
||||
/* /img/sics.gif (14 chars) */
|
||||
0x2f,0x69,0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x00,0x00,0x00,
|
||||
|
||||
/* HTTP header */
|
||||
/* "HTTP/1.0 200 OK
|
||||
" (17 bytes) */
|
||||
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
|
||||
0x0a,
|
||||
/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip)
|
||||
" (64 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30,
|
||||
0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,
|
||||
0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,
|
||||
0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
|
||||
/* "Content-Length: 724
|
||||
" (18+ bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,
|
||||
0x37,0x32,0x34,0x0d,0x0a,
|
||||
/* "Content-Type: image/gif
|
||||
|
||||
" (27 bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x69,0x6d,
|
||||
0x61,0x67,0x65,0x2f,0x67,0x69,0x66,0x0d,0x0a,0x0d,0x0a,
|
||||
/* raw file data (724 bytes) */
|
||||
0x47,0x49,0x46,0x38,0x39,0x61,0x46,0x00,0x22,0x00,0xa5,0x00,0x00,0xd9,0x2b,0x39,
|
||||
0x6a,0x6a,0x6a,0xbf,0xbf,0xbf,0x93,0x93,0x93,0x0f,0x0f,0x0f,0xb0,0xb0,0xb0,0xa6,
|
||||
0xa6,0xa6,0x80,0x80,0x80,0x76,0x76,0x76,0x1e,0x1e,0x1e,0x9d,0x9d,0x9d,0x2e,0x2e,
|
||||
0x2e,0x49,0x49,0x49,0x54,0x54,0x54,0x8a,0x8a,0x8a,0x60,0x60,0x60,0xc6,0xa6,0x99,
|
||||
0xbd,0xb5,0xb2,0xc2,0xab,0xa1,0xd9,0x41,0x40,0xd5,0x67,0x55,0xc0,0xb0,0xaa,0xd5,
|
||||
0x5e,0x4e,0xd6,0x50,0x45,0xcc,0x93,0x7d,0xc8,0xa1,0x90,0xce,0x8b,0x76,0xd2,0x7b,
|
||||
0x65,0xd1,0x84,0x6d,0xc9,0x99,0x86,0x3a,0x3a,0x3a,0x00,0x00,0x00,0xb8,0xb8,0xb8,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2c,0x00,0x00,
|
||||
0x00,0x00,0x46,0x00,0x22,0x00,0x00,0x06,0xfe,0x40,0x90,0x70,0x48,0x2c,0x1a,0x8f,
|
||||
0xc8,0xa4,0x72,0xc9,0x6c,0x3a,0x9f,0xd0,0xa8,0x74,0x4a,0xad,0x5a,0xaf,0xd8,0xac,
|
||||
0x76,0xa9,0x40,0x04,0xbe,0x83,0xe2,0x60,0x3c,0x50,0x20,0x0d,0x8e,0x6f,0x00,0x31,
|
||||
0x28,0x1c,0x0d,0x07,0xb5,0xc3,0x60,0x75,0x24,0x3e,0xf8,0xfc,0x87,0x11,0x06,0xe9,
|
||||
0x3d,0x46,0x07,0x0b,0x7a,0x7a,0x7c,0x43,0x06,0x1e,0x84,0x78,0x0b,0x07,0x6e,0x51,
|
||||
0x01,0x8a,0x84,0x08,0x7e,0x79,0x80,0x87,0x89,0x91,0x7a,0x93,0x0a,0x04,0x99,0x78,
|
||||
0x96,0x4f,0x03,0x9e,0x79,0x01,0x94,0x9f,0x43,0x9c,0xa3,0xa4,0x05,0x77,0xa3,0xa0,
|
||||
0x4e,0x98,0x79,0x0b,0x1e,0x83,0xa4,0xa6,0x1f,0x96,0x05,0x9d,0xaa,0x78,0x01,0x07,
|
||||
0x84,0x04,0x1e,0x1e,0xbb,0xb8,0x51,0x84,0x0e,0x43,0x05,0x07,0x77,0xa5,0x7f,0x42,
|
||||
0xb1,0xb2,0x01,0x63,0x08,0x0d,0xbb,0x01,0x0c,0x7a,0x0d,0x44,0x0e,0xd8,0xaf,0x4c,
|
||||
0x05,0x7a,0x04,0x47,0x07,0x07,0xb7,0x80,0xa2,0xe1,0x7d,0x44,0x05,0x01,0x04,0x01,
|
||||
0xd0,0xea,0x87,0x93,0x4f,0xe0,0x9a,0x49,0xce,0xd8,0x79,0x04,0x66,0x20,0x15,0x10,
|
||||
0x10,0x11,0x92,0x29,0x80,0xb6,0xc0,0x91,0x15,0x45,0x1e,0x90,0x19,0x71,0x46,0xa8,
|
||||
0x5c,0x04,0x0e,0x00,0x22,0x4e,0xe8,0x40,0x24,0x9f,0x3e,0x04,0x06,0xa7,0x58,0xd4,
|
||||
0x93,0xa0,0x1c,0x91,0x3f,0xe8,0xf0,0x88,0x03,0xb1,0x21,0xa2,0x49,0x00,0x19,0x86,
|
||||
0xfc,0x52,0x44,0xe0,0x01,0x9d,0x29,0x21,0x15,0x25,0x50,0xf7,0x67,0x25,0x1e,0x06,
|
||||
0xfd,0x4e,0x9a,0xb4,0x90,0xac,0x15,0xfa,0xcb,0x52,0x53,0x1e,0x8c,0xf2,0xf8,0x07,
|
||||
0x92,0x2d,0x08,0x3a,0x4d,0x12,0x49,0x95,0x49,0xdb,0x14,0x04,0xc4,0x14,0x85,0x29,
|
||||
0xaa,0xe7,0x01,0x08,0xa4,0x49,0x01,0x14,0x51,0xe0,0x53,0x91,0xd5,0x29,0x06,0x1a,
|
||||
0x64,0x02,0xf4,0xc7,0x81,0x9e,0x05,0x20,0x22,0x64,0xa5,0x30,0xae,0xab,0x9e,0x97,
|
||||
0x53,0xd8,0xb9,0xfd,0x50,0xef,0x93,0x02,0x42,0x74,0x34,0xe8,0x9c,0x20,0x21,0xc9,
|
||||
0x01,0x68,0x78,0xe6,0x55,0x29,0x20,0x56,0x4f,0x4c,0x40,0x51,0x71,0x82,0xc0,0x70,
|
||||
0x21,0x22,0x85,0xbe,0x4b,0x1c,0x44,0x05,0xea,0xa4,0x01,0xbf,0x22,0xb5,0xf0,0x1c,
|
||||
0x06,0x51,0x38,0x8f,0xe0,0x22,0xec,0x18,0xac,0x39,0x22,0xd4,0xd6,0x93,0x44,0x01,
|
||||
0x32,0x82,0xc8,0xfc,0x61,0xb3,0x01,0x45,0x0c,0x2e,0x83,0x30,0xd0,0x0e,0x17,0x24,
|
||||
0x0f,0x70,0x85,0x94,0xee,0x05,0x05,0x53,0x4b,0x32,0x1b,0x3f,0x98,0xd3,0x1d,0x29,
|
||||
0x81,0xb0,0xae,0x1e,0x8c,0x7e,0x68,0xe0,0x60,0x5a,0x54,0x8f,0xb0,0x78,0x69,0x73,
|
||||
0x06,0xa2,0x00,0x6b,0x57,0xca,0x3d,0x11,0x50,0xbd,0x04,0x30,0x4b,0x3a,0xd4,0xab,
|
||||
0x5f,0x1f,0x9b,0x3d,0x13,0x74,0x27,0x88,0x3c,0x25,0xe0,0x17,0xbe,0x7a,0x79,0x45,
|
||||
0x0d,0x0c,0xb0,0x8b,0xda,0x90,0xca,0x80,0x06,0x5d,0x17,0x60,0x1c,0x22,0x4c,0xd8,
|
||||
0x57,0x22,0x06,0x20,0x00,0x98,0x07,0x08,0xe4,0x56,0x80,0x80,0x1c,0xc5,0xb7,0xc5,
|
||||
0x82,0x0c,0x36,0xe8,0xe0,0x83,0x10,0x46,0x28,0xe1,0x84,0x14,0x56,0x68,0xa1,0x10,
|
||||
0x41,0x00,0x00,0x3b,};
|
||||
|
||||
#if FSDATA_FILE_ALIGNMENT==1
|
||||
static const unsigned int dummy_align__404_html = 1;
|
||||
#endif
|
||||
static const unsigned char FSDATA_ALIGN_PRE data__404_html[] FSDATA_ALIGN_POST = {
|
||||
/* /404.html (10 chars) */
|
||||
0x2f,0x34,0x30,0x34,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x00,
|
||||
|
||||
/* HTTP header */
|
||||
/* "HTTP/1.0 404 File not found
|
||||
" (29 bytes) */
|
||||
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x34,0x30,0x34,0x20,0x46,0x69,0x6c,
|
||||
0x65,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x0d,0x0a,
|
||||
/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip)
|
||||
" (64 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30,
|
||||
0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,
|
||||
0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,
|
||||
0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
|
||||
/* "Content-Length: 565
|
||||
" (18+ bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,
|
||||
0x35,0x36,0x35,0x0d,0x0a,
|
||||
/* "Content-Type: text/html
|
||||
|
||||
" (27 bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
|
||||
0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a,
|
||||
/* raw file data (565 bytes) */
|
||||
0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74,
|
||||
0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,
|
||||
0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,
|
||||
0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f,
|
||||
0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63,
|
||||
0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78,
|
||||
0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20,
|
||||
0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,
|
||||
0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74,
|
||||
0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c,
|
||||
0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20,
|
||||
0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
|
||||
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
|
||||
0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,
|
||||
0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20,
|
||||
0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,
|
||||
0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,
|
||||
0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f,
|
||||
0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69,
|
||||
0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09,
|
||||
0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,
|
||||
0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,
|
||||
0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20,
|
||||
0x20,0x3c,0x68,0x32,0x3e,0x34,0x30,0x34,0x20,0x2d,0x20,0x50,0x61,0x67,0x65,0x20,
|
||||
0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3c,0x2f,0x68,0x32,0x3e,0x0d,0x0a,
|
||||
0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x53,0x6f,0x72,
|
||||
0x72,0x79,0x2c,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,
|
||||
0x20,0x61,0x72,0x65,0x20,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x69,0x6e,0x67,0x20,
|
||||
0x77,0x61,0x73,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x6f,0x6e,
|
||||
0x20,0x74,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,
|
||||
0x65,0x72,0x2e,0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,
|
||||
0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e,
|
||||
0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72,
|
||||
0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,
|
||||
0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,
|
||||
0x6d,0x6c,0x3e,0x0d,0x0a,};
|
||||
|
||||
#if FSDATA_FILE_ALIGNMENT==1
|
||||
static const unsigned int dummy_align__index_html = 2;
|
||||
#endif
|
||||
static const unsigned char FSDATA_ALIGN_PRE data__index_html[] FSDATA_ALIGN_POST = {
|
||||
/* /index.html (12 chars) */
|
||||
0x2f,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x00,
|
||||
|
||||
/* HTTP header */
|
||||
/* "HTTP/1.0 200 OK
|
||||
" (17 bytes) */
|
||||
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
|
||||
0x0a,
|
||||
/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip)
|
||||
" (64 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30,
|
||||
0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,
|
||||
0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,
|
||||
0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
|
||||
/* "Content-Length: 1751
|
||||
" (18+ bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,
|
||||
0x31,0x37,0x35,0x31,0x0d,0x0a,
|
||||
/* "Content-Type: text/html
|
||||
|
||||
" (27 bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
|
||||
0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a,
|
||||
/* raw file data (1751 bytes) */
|
||||
0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74,
|
||||
0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,
|
||||
0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,
|
||||
0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f,
|
||||
0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63,
|
||||
0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78,
|
||||
0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20,
|
||||
0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,
|
||||
0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74,
|
||||
0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c,
|
||||
0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20,
|
||||
0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
|
||||
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
|
||||
0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,
|
||||
0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20,
|
||||
0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,
|
||||
0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,
|
||||
0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f,
|
||||
0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69,
|
||||
0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09,
|
||||
0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,
|
||||
0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,
|
||||
0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20,
|
||||
0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x77,
|
||||
0x65,0x62,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,0x20,0x61,0x72,0x65,0x20,
|
||||
0x77,0x61,0x74,0x63,0x68,0x69,0x6e,0x67,0x20,0x77,0x61,0x73,0x20,0x73,0x65,0x72,
|
||||
0x76,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x73,0x69,0x6d,0x70,0x6c,0x65,0x20,
|
||||
0x77,0x65,0x62,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,0x65,0x72,
|
||||
0x20,0x72,0x75,0x6e,0x6e,0x69,0x6e,0x67,0x20,0x6f,0x6e,0x20,0x74,0x6f,0x70,0x20,
|
||||
0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,
|
||||
0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20,0x73,0x74,0x61,0x63,0x6b,0x20,
|
||||
0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
|
||||
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
|
||||
0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x6c,
|
||||
0x77,0x49,0x50,0x3c,0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,
|
||||
0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,
|
||||
0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,
|
||||
0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,
|
||||
0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,
|
||||
0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,
|
||||
0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,
|
||||
0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,
|
||||
0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,
|
||||
0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,
|
||||
0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,
|
||||
0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,
|
||||
0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,
|
||||
0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,
|
||||
0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,
|
||||
0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,
|
||||
0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,
|
||||
0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,
|
||||
0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,
|
||||
0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,
|
||||
0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,
|
||||
0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,
|
||||
0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,
|
||||
0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,
|
||||
0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,
|
||||
0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,
|
||||
0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,
|
||||
0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,
|
||||
0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,
|
||||
0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,
|
||||
0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,
|
||||
0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,
|
||||
0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,
|
||||
0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,
|
||||
0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,
|
||||
0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x66,0x6f,0x63,0x75,0x73,0x20,0x6f,
|
||||
0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x54,0x43,0x50,0x2f,0x49,
|
||||
0x50,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,
|
||||
0x20,0x69,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x0d,0x0a,0x09,
|
||||
0x20,0x20,0x20,0x20,0x74,0x68,0x65,0x20,0x52,0x41,0x4d,0x20,0x75,0x73,0x61,0x67,
|
||||
0x65,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x73,0x74,0x69,0x6c,0x6c,0x20,0x68,0x61,
|
||||
0x76,0x69,0x6e,0x67,0x20,0x61,0x20,0x66,0x75,0x6c,0x6c,0x20,0x73,0x63,0x61,0x6c,
|
||||
0x65,0x20,0x54,0x43,0x50,0x2e,0x20,0x54,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,
|
||||
0x20,0x20,0x6d,0x61,0x6b,0x65,0x73,0x20,0x6c,0x77,0x49,0x50,0x20,0x73,0x75,0x69,
|
||||
0x74,0x61,0x62,0x6c,0x65,0x20,0x66,0x6f,0x72,0x20,0x75,0x73,0x65,0x20,0x69,0x6e,
|
||||
0x20,0x65,0x6d,0x62,0x65,0x64,0x64,0x65,0x64,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,
|
||||
0x73,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x65,0x6e,0x73,0x0d,0x0a,0x09,0x20,0x20,
|
||||
0x20,0x20,0x6f,0x66,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x20,0x6f,
|
||||
0x66,0x20,0x66,0x72,0x65,0x65,0x20,0x52,0x41,0x4d,0x20,0x61,0x6e,0x64,0x20,0x72,
|
||||
0x6f,0x6f,0x6d,0x20,0x66,0x6f,0x72,0x20,0x61,0x72,0x6f,0x75,0x6e,0x64,0x20,0x34,
|
||||
0x30,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x0d,0x0a,0x09,0x20,0x20,
|
||||
0x20,0x20,0x6f,0x66,0x20,0x63,0x6f,0x64,0x65,0x20,0x52,0x4f,0x4d,0x2e,0x0d,0x0a,
|
||||
0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,
|
||||
0x0a,0x09,0x20,0x20,0x20,0x20,0x4d,0x6f,0x72,0x65,0x20,0x69,0x6e,0x66,0x6f,0x72,
|
||||
0x6d,0x61,0x74,0x69,0x6f,0x6e,0x20,0x61,0x62,0x6f,0x75,0x74,0x20,0x6c,0x77,0x49,
|
||||
0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x61,
|
||||
0x74,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,
|
||||
0x20,0x68,0x6f,0x6d,0x65,0x70,0x61,0x67,0x65,0x20,0x61,0x74,0x20,0x3c,0x61,0x0d,
|
||||
0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,
|
||||
0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,
|
||||
0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,
|
||||
0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,
|
||||
0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,
|
||||
0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x2f,
|
||||
0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x72,0x20,0x61,0x74,
|
||||
0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x77,0x69,0x6b,0x69,0x20,0x61,
|
||||
0x74,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,
|
||||
0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,
|
||||
0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
|
||||
0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x3c,
|
||||
0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,
|
||||
0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e,
|
||||
0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72,
|
||||
0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,
|
||||
0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,
|
||||
0x6d,0x6c,0x3e,0x0d,0x0a,0x0d,0x0a,};
|
||||
|
||||
|
||||
|
||||
const struct fsdata_file file__img_sics_gif[] = { {
|
||||
file_NULL,
|
||||
data__img_sics_gif,
|
||||
data__img_sics_gif + 16,
|
||||
sizeof(data__img_sics_gif) - 16,
|
||||
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
|
||||
}};
|
||||
|
||||
const struct fsdata_file file__404_html[] = { {
|
||||
file__img_sics_gif,
|
||||
data__404_html,
|
||||
data__404_html + 12,
|
||||
sizeof(data__404_html) - 12,
|
||||
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
|
||||
}};
|
||||
|
||||
const struct fsdata_file file__index_html[] = { {
|
||||
file__404_html,
|
||||
data__index_html,
|
||||
data__index_html + 12,
|
||||
sizeof(data__index_html) - 12,
|
||||
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
|
||||
}};
|
||||
|
||||
#define FS_ROOT file__index_html
|
||||
#define FS_NUMFILES 3
|
||||
|
41
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fsdata.h
Normal file
41
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/fsdata.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef LWIP_FSDATA_H
|
||||
#define LWIP_FSDATA_H
|
||||
|
||||
#include "lwip/apps/httpd_opts.h"
|
||||
#include "lwip/apps/fs.h"
|
||||
|
||||
/* THIS FILE IS DEPRECATED AND WILL BE REMOVED IN THE FUTURE */
|
||||
/* content was moved to fs.h to simplify #include structure */
|
||||
|
||||
#endif /* LWIP_FSDATA_H */
|
909
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/http_client.c
Normal file
909
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/http_client.c
Normal file
@ -0,0 +1,909 @@
|
||||
/**
|
||||
* @file
|
||||
* HTTP client
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Simon Goldschmidt <goldsimon@gmx.de>
|
||||
* 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt <goldsimon@gmx.de>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup httpc HTTP client
|
||||
* @ingroup apps
|
||||
* @todo:
|
||||
* - persistent connections
|
||||
* - select outgoing http version
|
||||
* - optionally follow redirect
|
||||
* - check request uri for invalid characters? (e.g. encode spaces)
|
||||
* - IPv6 support
|
||||
*/
|
||||
|
||||
#include "lwip/apps/http_client.h"
|
||||
|
||||
#include "lwip/altcp_tcp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/debug.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/altcp_tls.h"
|
||||
#include "lwip/init.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if LWIP_TCP && LWIP_CALLBACK_API
|
||||
|
||||
/**
|
||||
* HTTPC_DEBUG: Enable debugging for HTTP client.
|
||||
*/
|
||||
#ifndef HTTPC_DEBUG
|
||||
#define HTTPC_DEBUG LWIP_DBG_OFF
|
||||
#endif
|
||||
|
||||
/** Set this to 1 to keep server name and uri in request state */
|
||||
#ifndef HTTPC_DEBUG_REQUEST
|
||||
#define HTTPC_DEBUG_REQUEST 0
|
||||
#endif
|
||||
|
||||
/** This string is passed in the HTTP header as "User-Agent: " */
|
||||
#ifndef HTTPC_CLIENT_AGENT
|
||||
#define HTTPC_CLIENT_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)"
|
||||
#endif
|
||||
|
||||
/* the various debug levels for this file */
|
||||
#define HTTPC_DEBUG_TRACE (HTTPC_DEBUG | LWIP_DBG_TRACE)
|
||||
#define HTTPC_DEBUG_STATE (HTTPC_DEBUG | LWIP_DBG_STATE)
|
||||
#define HTTPC_DEBUG_WARN (HTTPC_DEBUG | LWIP_DBG_LEVEL_WARNING)
|
||||
#define HTTPC_DEBUG_WARN_STATE (HTTPC_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
|
||||
#define HTTPC_DEBUG_SERIOUS (HTTPC_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
|
||||
|
||||
#define HTTPC_POLL_INTERVAL 1
|
||||
#define HTTPC_POLL_TIMEOUT 30 /* 15 seconds */
|
||||
|
||||
#define HTTPC_CONTENT_LEN_INVALID 0xFFFFFFFF
|
||||
|
||||
/* GET request basic */
|
||||
#define HTTPC_REQ_11 "GET %s HTTP/1.1\r\n" /* URI */\
|
||||
"User-Agent: %s\r\n" /* User-Agent */ \
|
||||
"Accept: */*\r\n" \
|
||||
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
|
||||
"\r\n"
|
||||
#define HTTPC_REQ_11_FORMAT(uri) HTTPC_REQ_11, uri, HTTPC_CLIENT_AGENT
|
||||
|
||||
/* GET request with host */
|
||||
#define HTTPC_REQ_11_HOST "GET %s HTTP/1.1\r\n" /* URI */\
|
||||
"User-Agent: %s\r\n" /* User-Agent */ \
|
||||
"Accept: */*\r\n" \
|
||||
"Host: %s\r\n" /* server name */ \
|
||||
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
|
||||
"\r\n"
|
||||
#define HTTPC_REQ_11_HOST_FORMAT(uri, srv_name) HTTPC_REQ_11_HOST, uri, HTTPC_CLIENT_AGENT, srv_name
|
||||
|
||||
/* GET request with proxy */
|
||||
#define HTTPC_REQ_11_PROXY "GET http://%s%s HTTP/1.1\r\n" /* HOST, URI */\
|
||||
"User-Agent: %s\r\n" /* User-Agent */ \
|
||||
"Accept: */*\r\n" \
|
||||
"Host: %s\r\n" /* server name */ \
|
||||
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
|
||||
"\r\n"
|
||||
#define HTTPC_REQ_11_PROXY_FORMAT(host, uri, srv_name) HTTPC_REQ_11_PROXY, host, uri, HTTPC_CLIENT_AGENT, srv_name
|
||||
|
||||
/* GET request with proxy (non-default server port) */
|
||||
#define HTTPC_REQ_11_PROXY_PORT "GET http://%s:%d%s HTTP/1.1\r\n" /* HOST, host-port, URI */\
|
||||
"User-Agent: %s\r\n" /* User-Agent */ \
|
||||
"Accept: */*\r\n" \
|
||||
"Host: %s\r\n" /* server name */ \
|
||||
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
|
||||
"\r\n"
|
||||
#define HTTPC_REQ_11_PROXY_PORT_FORMAT(host, host_port, uri, srv_name) HTTPC_REQ_11_PROXY_PORT, host, host_port, uri, HTTPC_CLIENT_AGENT, srv_name
|
||||
|
||||
typedef enum ehttpc_parse_state {
|
||||
HTTPC_PARSE_WAIT_FIRST_LINE = 0,
|
||||
HTTPC_PARSE_WAIT_HEADERS,
|
||||
HTTPC_PARSE_RX_DATA
|
||||
} httpc_parse_state_t;
|
||||
|
||||
typedef struct _httpc_state
|
||||
{
|
||||
struct altcp_pcb* pcb;
|
||||
ip_addr_t remote_addr;
|
||||
u16_t remote_port;
|
||||
int timeout_ticks;
|
||||
struct pbuf *request;
|
||||
struct pbuf *rx_hdrs;
|
||||
u16_t rx_http_version;
|
||||
u16_t rx_status;
|
||||
altcp_recv_fn recv_fn;
|
||||
const httpc_connection_t *conn_settings;
|
||||
void* callback_arg;
|
||||
u32_t rx_content_len;
|
||||
u32_t hdr_content_len;
|
||||
httpc_parse_state_t parse_state;
|
||||
#if HTTPC_DEBUG_REQUEST
|
||||
char* server_name;
|
||||
char* uri;
|
||||
#endif
|
||||
} httpc_state_t;
|
||||
|
||||
/** Free http client state and deallocate all resources within */
|
||||
static err_t
|
||||
httpc_free_state(httpc_state_t* req)
|
||||
{
|
||||
struct altcp_pcb* tpcb;
|
||||
|
||||
if (req->request != NULL) {
|
||||
pbuf_free(req->request);
|
||||
req->request = NULL;
|
||||
}
|
||||
if (req->rx_hdrs != NULL) {
|
||||
pbuf_free(req->rx_hdrs);
|
||||
req->rx_hdrs = NULL;
|
||||
}
|
||||
|
||||
tpcb = req->pcb;
|
||||
mem_free(req);
|
||||
req = NULL;
|
||||
|
||||
if (tpcb != NULL) {
|
||||
err_t r;
|
||||
altcp_arg(tpcb, NULL);
|
||||
altcp_recv(tpcb, NULL);
|
||||
altcp_err(tpcb, NULL);
|
||||
altcp_poll(tpcb, NULL, 0);
|
||||
altcp_sent(tpcb, NULL);
|
||||
r = altcp_close(tpcb);
|
||||
if (r != ERR_OK) {
|
||||
altcp_abort(tpcb);
|
||||
return ERR_ABRT;
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Close the connection: call finished callback and free the state */
|
||||
static err_t
|
||||
httpc_close(httpc_state_t* req, httpc_result_t result, u32_t server_response, err_t err)
|
||||
{
|
||||
if (req != NULL) {
|
||||
if (req->conn_settings != NULL) {
|
||||
if (req->conn_settings->result_fn != NULL) {
|
||||
req->conn_settings->result_fn(req->callback_arg, result, req->rx_content_len, server_response, err);
|
||||
}
|
||||
}
|
||||
return httpc_free_state(req);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Parse http header response line 1 */
|
||||
static err_t
|
||||
http_parse_response_status(struct pbuf *p, u16_t *http_version, u16_t *http_status, u16_t *http_status_str_offset)
|
||||
{
|
||||
u16_t end1 = pbuf_memfind(p, "\r\n", 2, 0);
|
||||
if (end1 != 0xFFFF) {
|
||||
/* get parts of first line */
|
||||
u16_t space1, space2;
|
||||
space1 = pbuf_memfind(p, " ", 1, 0);
|
||||
if (space1 != 0xFFFF) {
|
||||
if ((pbuf_memcmp(p, 0, "HTTP/", 5) == 0) && (pbuf_get_at(p, 6) == '.')) {
|
||||
char status_num[10];
|
||||
size_t status_num_len;
|
||||
/* parse http version */
|
||||
u16_t version = pbuf_get_at(p, 5) - '0';
|
||||
version <<= 8;
|
||||
version |= pbuf_get_at(p, 7) - '0';
|
||||
*http_version = version;
|
||||
|
||||
/* parse http status number */
|
||||
space2 = pbuf_memfind(p, " ", 1, space1 + 1);
|
||||
if (space2 != 0xFFFF) {
|
||||
*http_status_str_offset = space2 + 1;
|
||||
status_num_len = space2 - space1 - 1;
|
||||
} else {
|
||||
status_num_len = end1 - space1 - 1;
|
||||
}
|
||||
memset(status_num, 0, sizeof(status_num));
|
||||
if (pbuf_copy_partial(p, status_num, (u16_t)status_num_len, space1 + 1) == status_num_len) {
|
||||
int status = atoi(status_num);
|
||||
if ((status > 0) && (status <= 0xFFFF)) {
|
||||
*http_status = (u16_t)status;
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/** Wait for all headers to be received, return its length and content-length (if available) */
|
||||
static err_t
|
||||
http_wait_headers(struct pbuf *p, u32_t *content_length, u16_t *total_header_len)
|
||||
{
|
||||
u16_t end1 = pbuf_memfind(p, "\r\n\r\n", 4, 0);
|
||||
if (end1 < (0xFFFF - 2)) {
|
||||
/* all headers received */
|
||||
/* check if we have a content length (@todo: case insensitive?) */
|
||||
u16_t content_len_hdr;
|
||||
*content_length = HTTPC_CONTENT_LEN_INVALID;
|
||||
*total_header_len = end1 + 4;
|
||||
|
||||
content_len_hdr = pbuf_memfind(p, "Content-Length: ", 16, 0);
|
||||
if (content_len_hdr != 0xFFFF) {
|
||||
u16_t content_len_line_end = pbuf_memfind(p, "\r\n", 2, content_len_hdr);
|
||||
if (content_len_line_end != 0xFFFF) {
|
||||
char content_len_num[16];
|
||||
u16_t content_len_num_len = (u16_t)(content_len_line_end - content_len_hdr - 16);
|
||||
memset(content_len_num, 0, sizeof(content_len_num));
|
||||
if (pbuf_copy_partial(p, content_len_num, content_len_num_len, content_len_hdr + 16) == content_len_num_len) {
|
||||
int len = atoi(content_len_num);
|
||||
if ((len >= 0) && ((u32_t)len < HTTPC_CONTENT_LEN_INVALID)) {
|
||||
*content_length = (u32_t)len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/** http client tcp recv callback */
|
||||
static err_t
|
||||
httpc_tcp_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t r)
|
||||
{
|
||||
httpc_state_t* req = (httpc_state_t*)arg;
|
||||
LWIP_UNUSED_ARG(r);
|
||||
|
||||
if (p == NULL) {
|
||||
httpc_result_t result;
|
||||
if (req->parse_state != HTTPC_PARSE_RX_DATA) {
|
||||
/* did not get RX data yet */
|
||||
result = HTTPC_RESULT_ERR_CLOSED;
|
||||
} else if ((req->hdr_content_len != HTTPC_CONTENT_LEN_INVALID) &&
|
||||
(req->hdr_content_len != req->rx_content_len)) {
|
||||
/* header has been received with content length but not all data received */
|
||||
result = HTTPC_RESULT_ERR_CONTENT_LEN;
|
||||
} else {
|
||||
/* receiving data and either all data received or no content length header */
|
||||
result = HTTPC_RESULT_OK;
|
||||
}
|
||||
return httpc_close(req, result, req->rx_status, ERR_OK);
|
||||
}
|
||||
if (req->parse_state != HTTPC_PARSE_RX_DATA) {
|
||||
if (req->rx_hdrs == NULL) {
|
||||
req->rx_hdrs = p;
|
||||
} else {
|
||||
pbuf_cat(req->rx_hdrs, p);
|
||||
}
|
||||
if (req->parse_state == HTTPC_PARSE_WAIT_FIRST_LINE) {
|
||||
u16_t status_str_off;
|
||||
err_t err = http_parse_response_status(req->rx_hdrs, &req->rx_http_version, &req->rx_status, &status_str_off);
|
||||
if (err == ERR_OK) {
|
||||
/* don't care status string */
|
||||
req->parse_state = HTTPC_PARSE_WAIT_HEADERS;
|
||||
}
|
||||
}
|
||||
if (req->parse_state == HTTPC_PARSE_WAIT_HEADERS) {
|
||||
u16_t total_header_len;
|
||||
err_t err = http_wait_headers(req->rx_hdrs, &req->hdr_content_len, &total_header_len);
|
||||
if (err == ERR_OK) {
|
||||
struct pbuf *q;
|
||||
/* full header received, send window update for header bytes and call into client callback */
|
||||
altcp_recved(pcb, total_header_len);
|
||||
if (req->conn_settings) {
|
||||
if (req->conn_settings->headers_done_fn) {
|
||||
err = req->conn_settings->headers_done_fn(req, req->callback_arg, req->rx_hdrs, total_header_len, req->hdr_content_len);
|
||||
if (err != ERR_OK) {
|
||||
return httpc_close(req, HTTPC_RESULT_LOCAL_ABORT, req->rx_status, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* hide header bytes in pbuf */
|
||||
q = pbuf_free_header(req->rx_hdrs, total_header_len);
|
||||
p = q;
|
||||
req->rx_hdrs = NULL;
|
||||
/* go on with data */
|
||||
req->parse_state = HTTPC_PARSE_RX_DATA;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((p != NULL) && (req->parse_state == HTTPC_PARSE_RX_DATA)) {
|
||||
req->rx_content_len += p->tot_len;
|
||||
if (req->recv_fn != NULL) {
|
||||
/* directly return here: the connection migth already be aborted from the callback! */
|
||||
return req->recv_fn(req->callback_arg, pcb, p, r);
|
||||
} else {
|
||||
altcp_recved(pcb, p->tot_len);
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** http client tcp err callback */
|
||||
static void
|
||||
httpc_tcp_err(void *arg, err_t err)
|
||||
{
|
||||
httpc_state_t* req = (httpc_state_t*)arg;
|
||||
if (req != NULL) {
|
||||
/* pcb has already been deallocated */
|
||||
req->pcb = NULL;
|
||||
httpc_close(req, HTTPC_RESULT_ERR_CLOSED, 0, err);
|
||||
}
|
||||
}
|
||||
|
||||
/** http client tcp poll callback */
|
||||
static err_t
|
||||
httpc_tcp_poll(void *arg, struct altcp_pcb *pcb)
|
||||
{
|
||||
/* implement timeout */
|
||||
httpc_state_t* req = (httpc_state_t*)arg;
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
if (req != NULL) {
|
||||
if (req->timeout_ticks) {
|
||||
req->timeout_ticks--;
|
||||
}
|
||||
if (!req->timeout_ticks) {
|
||||
return httpc_close(req, HTTPC_RESULT_ERR_TIMEOUT, 0, ERR_OK);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** http client tcp sent callback */
|
||||
static err_t
|
||||
httpc_tcp_sent(void *arg, struct altcp_pcb *pcb, u16_t len)
|
||||
{
|
||||
/* nothing to do here for now */
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
LWIP_UNUSED_ARG(len);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** http client tcp connected callback */
|
||||
static err_t
|
||||
httpc_tcp_connected(void *arg, struct altcp_pcb *pcb, err_t err)
|
||||
{
|
||||
err_t r;
|
||||
httpc_state_t* req = (httpc_state_t*)arg;
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
LWIP_UNUSED_ARG(err);
|
||||
|
||||
/* send request; last char is zero termination */
|
||||
r = altcp_write(req->pcb, req->request->payload, req->request->len - 1, TCP_WRITE_FLAG_COPY);
|
||||
if (r != ERR_OK) {
|
||||
/* could not write the single small request -> fail, don't retry */
|
||||
return httpc_close(req, HTTPC_RESULT_ERR_MEM, 0, r);
|
||||
}
|
||||
/* everything written, we can free the request */
|
||||
pbuf_free(req->request);
|
||||
req->request = NULL;
|
||||
|
||||
altcp_output(req->pcb);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Start the http request when the server IP addr is known */
|
||||
static err_t
|
||||
httpc_get_internal_addr(httpc_state_t* req, const ip_addr_t *ipaddr)
|
||||
{
|
||||
err_t err;
|
||||
LWIP_ASSERT("req != NULL", req != NULL);
|
||||
|
||||
if (&req->remote_addr != ipaddr) {
|
||||
/* fill in remote addr if called externally */
|
||||
req->remote_addr = *ipaddr;
|
||||
}
|
||||
|
||||
err = altcp_connect(req->pcb, &req->remote_addr, req->remote_port, httpc_tcp_connected);
|
||||
if (err == ERR_OK) {
|
||||
return ERR_OK;
|
||||
}
|
||||
LWIP_DEBUGF(HTTPC_DEBUG_WARN_STATE, ("tcp_connect failed: %d\n", (int)err));
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LWIP_DNS
|
||||
/** DNS callback
|
||||
* If ipaddr is non-NULL, resolving succeeded and the request can be sent, otherwise it failed.
|
||||
*/
|
||||
static void
|
||||
httpc_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
|
||||
{
|
||||
httpc_state_t* req = (httpc_state_t*)arg;
|
||||
err_t err;
|
||||
httpc_result_t result;
|
||||
|
||||
LWIP_UNUSED_ARG(hostname);
|
||||
|
||||
if (ipaddr != NULL) {
|
||||
err = httpc_get_internal_addr(req, ipaddr);
|
||||
if (err == ERR_OK) {
|
||||
return;
|
||||
}
|
||||
result = HTTPC_RESULT_ERR_CONNECT;
|
||||
} else {
|
||||
LWIP_DEBUGF(HTTPC_DEBUG_WARN_STATE, ("httpc_dns_found: failed to resolve hostname: %s\n",
|
||||
hostname));
|
||||
result = HTTPC_RESULT_ERR_HOSTNAME;
|
||||
err = ERR_ARG;
|
||||
}
|
||||
httpc_close(req, result, 0, err);
|
||||
}
|
||||
#endif /* LWIP_DNS */
|
||||
|
||||
/** Start the http request after converting 'server_name' to ip address (DNS or address string) */
|
||||
static err_t
|
||||
httpc_get_internal_dns(httpc_state_t* req, const char* server_name)
|
||||
{
|
||||
err_t err;
|
||||
LWIP_ASSERT("req != NULL", req != NULL);
|
||||
|
||||
#if LWIP_DNS
|
||||
err = dns_gethostbyname(server_name, &req->remote_addr, httpc_dns_found, req);
|
||||
#else
|
||||
err = ipaddr_aton(server_name, &req->remote_addr) ? ERR_OK : ERR_ARG;
|
||||
#endif
|
||||
|
||||
if (err == ERR_OK) {
|
||||
/* cached or IP-string */
|
||||
err = httpc_get_internal_addr(req, &req->remote_addr);
|
||||
} else if (err == ERR_INPROGRESS) {
|
||||
return ERR_OK;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
httpc_create_request_string(const httpc_connection_t *settings, const char* server_name, int server_port, const char* uri,
|
||||
int use_host, char *buffer, size_t buffer_size)
|
||||
{
|
||||
if (settings->use_proxy) {
|
||||
LWIP_ASSERT("server_name != NULL", server_name != NULL);
|
||||
if (server_port != HTTP_DEFAULT_PORT) {
|
||||
return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_PORT_FORMAT(server_name, server_port, uri, server_name));
|
||||
} else {
|
||||
return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_FORMAT(server_name, uri, server_name));
|
||||
}
|
||||
} else if (use_host) {
|
||||
LWIP_ASSERT("server_name != NULL", server_name != NULL);
|
||||
return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT(uri, server_name));
|
||||
} else {
|
||||
return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT(uri));
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize the connection struct */
|
||||
static err_t
|
||||
httpc_init_connection_common(httpc_state_t **connection, const httpc_connection_t *settings, const char* server_name,
|
||||
u16_t server_port, const char* uri, altcp_recv_fn recv_fn, void* callback_arg, int use_host)
|
||||
{
|
||||
size_t alloc_len;
|
||||
mem_size_t mem_alloc_len;
|
||||
int req_len, req_len2;
|
||||
httpc_state_t *req;
|
||||
#if HTTPC_DEBUG_REQUEST
|
||||
size_t server_name_len, uri_len;
|
||||
#endif
|
||||
|
||||
LWIP_ASSERT("uri != NULL", uri != NULL);
|
||||
|
||||
/* get request len */
|
||||
req_len = httpc_create_request_string(settings, server_name, server_port, uri, use_host, NULL, 0);
|
||||
if ((req_len < 0) || (req_len > 0xFFFF)) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
/* alloc state and request in one block */
|
||||
alloc_len = sizeof(httpc_state_t);
|
||||
#if HTTPC_DEBUG_REQUEST
|
||||
server_name_len = server_name ? strlen(server_name) : 0;
|
||||
uri_len = strlen(uri);
|
||||
alloc_len += server_name_len + 1 + uri_len + 1;
|
||||
#endif
|
||||
mem_alloc_len = (mem_size_t)alloc_len;
|
||||
if ((mem_alloc_len < alloc_len) || (req_len + 1 > 0xFFFF)) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
req = (httpc_state_t*)mem_malloc((mem_size_t)alloc_len);
|
||||
if(req == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(req, 0, sizeof(httpc_state_t));
|
||||
req->timeout_ticks = HTTPC_POLL_TIMEOUT;
|
||||
req->request = pbuf_alloc(PBUF_RAW, (u16_t)(req_len + 1), PBUF_RAM);
|
||||
if (req->request == NULL) {
|
||||
httpc_free_state(req);
|
||||
return ERR_MEM;
|
||||
}
|
||||
if (req->request->next != NULL) {
|
||||
/* need a pbuf in one piece */
|
||||
httpc_free_state(req);
|
||||
return ERR_MEM;
|
||||
}
|
||||
req->hdr_content_len = HTTPC_CONTENT_LEN_INVALID;
|
||||
#if HTTPC_DEBUG_REQUEST
|
||||
req->server_name = (char*)(req + 1);
|
||||
if (server_name) {
|
||||
memcpy(req->server_name, server_name, server_name_len + 1);
|
||||
}
|
||||
req->uri = req->server_name + server_name_len + 1;
|
||||
memcpy(req->uri, uri, uri_len + 1);
|
||||
#endif
|
||||
req->pcb = altcp_new(settings->altcp_allocator);
|
||||
if(req->pcb == NULL) {
|
||||
httpc_free_state(req);
|
||||
return ERR_MEM;
|
||||
}
|
||||
req->remote_port = settings->use_proxy ? settings->proxy_port : server_port;
|
||||
altcp_arg(req->pcb, req);
|
||||
altcp_recv(req->pcb, httpc_tcp_recv);
|
||||
altcp_err(req->pcb, httpc_tcp_err);
|
||||
altcp_poll(req->pcb, httpc_tcp_poll, HTTPC_POLL_INTERVAL);
|
||||
altcp_sent(req->pcb, httpc_tcp_sent);
|
||||
|
||||
/* set up request buffer */
|
||||
req_len2 = httpc_create_request_string(settings, server_name, server_port, uri, use_host,
|
||||
(char *)req->request->payload, req_len + 1);
|
||||
if (req_len2 != req_len) {
|
||||
httpc_free_state(req);
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
req->recv_fn = recv_fn;
|
||||
req->conn_settings = settings;
|
||||
req->callback_arg = callback_arg;
|
||||
|
||||
*connection = req;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the connection struct
|
||||
*/
|
||||
static err_t
|
||||
httpc_init_connection(httpc_state_t **connection, const httpc_connection_t *settings, const char* server_name,
|
||||
u16_t server_port, const char* uri, altcp_recv_fn recv_fn, void* callback_arg)
|
||||
{
|
||||
return httpc_init_connection_common(connection, settings, server_name, server_port, uri, recv_fn, callback_arg, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the connection struct (from IP address)
|
||||
*/
|
||||
static err_t
|
||||
httpc_init_connection_addr(httpc_state_t **connection, const httpc_connection_t *settings,
|
||||
const ip_addr_t* server_addr, u16_t server_port, const char* uri,
|
||||
altcp_recv_fn recv_fn, void* callback_arg)
|
||||
{
|
||||
char *server_addr_str = ipaddr_ntoa(server_addr);
|
||||
if (server_addr_str == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
return httpc_init_connection_common(connection, settings, server_addr_str, server_port, uri,
|
||||
recv_fn, callback_arg, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup httpc
|
||||
* HTTP client API: get a file by passing server IP address
|
||||
*
|
||||
* @param server_addr IP address of the server to connect
|
||||
* @param port tcp port of the server
|
||||
* @param uri uri to get from the server, remember leading "/"!
|
||||
* @param settings connection settings (callbacks, proxy, etc.)
|
||||
* @param recv_fn the http body (not the headers) are passed to this callback
|
||||
* @param callback_arg argument passed to all the callbacks
|
||||
* @param connection retreives the connection handle (to match in callbacks)
|
||||
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
|
||||
* or an error code
|
||||
*/
|
||||
err_t
|
||||
httpc_get_file(const ip_addr_t* server_addr, u16_t port, const char* uri, const httpc_connection_t *settings,
|
||||
altcp_recv_fn recv_fn, void* callback_arg, httpc_state_t **connection)
|
||||
{
|
||||
err_t err;
|
||||
httpc_state_t* req;
|
||||
|
||||
LWIP_ERROR("invalid parameters", (server_addr != NULL) && (uri != NULL) && (recv_fn != NULL), return ERR_ARG;);
|
||||
|
||||
err = httpc_init_connection_addr(&req, settings, server_addr, port,
|
||||
uri, recv_fn, callback_arg);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (settings->use_proxy) {
|
||||
err = httpc_get_internal_addr(req, &settings->proxy_addr);
|
||||
} else {
|
||||
err = httpc_get_internal_addr(req, server_addr);
|
||||
}
|
||||
if(err != ERR_OK) {
|
||||
httpc_free_state(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (connection != NULL) {
|
||||
*connection = req;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup httpc
|
||||
* HTTP client API: get a file by passing server name as string (DNS name or IP address string)
|
||||
*
|
||||
* @param server_name server name as string (DNS name or IP address string)
|
||||
* @param port tcp port of the server
|
||||
* @param uri uri to get from the server, remember leading "/"!
|
||||
* @param settings connection settings (callbacks, proxy, etc.)
|
||||
* @param recv_fn the http body (not the headers) are passed to this callback
|
||||
* @param callback_arg argument passed to all the callbacks
|
||||
* @param connection retreives the connection handle (to match in callbacks)
|
||||
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
|
||||
* or an error code
|
||||
*/
|
||||
err_t
|
||||
httpc_get_file_dns(const char* server_name, u16_t port, const char* uri, const httpc_connection_t *settings,
|
||||
altcp_recv_fn recv_fn, void* callback_arg, httpc_state_t **connection)
|
||||
{
|
||||
err_t err;
|
||||
httpc_state_t* req;
|
||||
|
||||
LWIP_ERROR("invalid parameters", (server_name != NULL) && (uri != NULL) && (recv_fn != NULL), return ERR_ARG;);
|
||||
|
||||
err = httpc_init_connection(&req, settings, server_name, port, uri, recv_fn, callback_arg);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (settings->use_proxy) {
|
||||
err = httpc_get_internal_addr(req, &settings->proxy_addr);
|
||||
} else {
|
||||
err = httpc_get_internal_dns(req, server_name);
|
||||
}
|
||||
if(err != ERR_OK) {
|
||||
httpc_free_state(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (connection != NULL) {
|
||||
*connection = req;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if LWIP_HTTPC_HAVE_FILE_IO
|
||||
/* Implementation to disk via fopen/fwrite/fclose follows */
|
||||
|
||||
typedef struct _httpc_filestate
|
||||
{
|
||||
const char* local_file_name;
|
||||
FILE *file;
|
||||
httpc_connection_t settings;
|
||||
const httpc_connection_t *client_settings;
|
||||
void *callback_arg;
|
||||
} httpc_filestate_t;
|
||||
|
||||
static void httpc_fs_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len,
|
||||
u32_t srv_res, err_t err);
|
||||
|
||||
/** Initalize http client state for download to file system */
|
||||
static err_t
|
||||
httpc_fs_init(httpc_filestate_t **filestate_out, const char* local_file_name,
|
||||
const httpc_connection_t *settings, void* callback_arg)
|
||||
{
|
||||
httpc_filestate_t *filestate;
|
||||
size_t file_len, alloc_len;
|
||||
FILE *f;
|
||||
|
||||
file_len = strlen(local_file_name);
|
||||
alloc_len = sizeof(httpc_filestate_t) + file_len + 1;
|
||||
|
||||
filestate = (httpc_filestate_t *)mem_malloc((mem_size_t)alloc_len);
|
||||
if (filestate == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(filestate, 0, sizeof(httpc_filestate_t));
|
||||
filestate->local_file_name = (const char *)(filestate + 1);
|
||||
memcpy((char *)(filestate + 1), local_file_name, file_len + 1);
|
||||
filestate->file = NULL;
|
||||
filestate->client_settings = settings;
|
||||
filestate->callback_arg = callback_arg;
|
||||
/* copy client settings but override result callback */
|
||||
memcpy(&filestate->settings, settings, sizeof(httpc_connection_t));
|
||||
filestate->settings.result_fn = httpc_fs_result;
|
||||
|
||||
f = fopen(local_file_name, "wb");
|
||||
if(f == NULL) {
|
||||
/* could not open file */
|
||||
mem_free(filestate);
|
||||
return ERR_VAL;
|
||||
}
|
||||
filestate->file = f;
|
||||
*filestate_out = filestate;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Free http client state for download to file system */
|
||||
static void
|
||||
httpc_fs_free(httpc_filestate_t *filestate)
|
||||
{
|
||||
if (filestate != NULL) {
|
||||
if (filestate->file != NULL) {
|
||||
fclose(filestate->file);
|
||||
filestate->file = NULL;
|
||||
}
|
||||
mem_free(filestate);
|
||||
}
|
||||
}
|
||||
|
||||
/** Connection closed (success or error) */
|
||||
static void
|
||||
httpc_fs_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len,
|
||||
u32_t srv_res, err_t err)
|
||||
{
|
||||
httpc_filestate_t *filestate = (httpc_filestate_t *)arg;
|
||||
if (filestate != NULL) {
|
||||
if (filestate->client_settings->result_fn != NULL) {
|
||||
filestate->client_settings->result_fn(filestate->callback_arg, httpc_result, rx_content_len,
|
||||
srv_res, err);
|
||||
}
|
||||
httpc_fs_free(filestate);
|
||||
}
|
||||
}
|
||||
|
||||
/** tcp recv callback */
|
||||
static err_t
|
||||
httpc_fs_tcp_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err)
|
||||
{
|
||||
httpc_filestate_t *filestate = (httpc_filestate_t*)arg;
|
||||
struct pbuf* q;
|
||||
LWIP_UNUSED_ARG(err);
|
||||
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
fwrite(q->payload, 1, q->len, filestate->file);
|
||||
}
|
||||
altcp_recved(pcb, p->tot_len);
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup httpc
|
||||
* HTTP client API: get a file to disk by passing server IP address
|
||||
*
|
||||
* @param server_addr IP address of the server to connect
|
||||
* @param port tcp port of the server
|
||||
* @param uri uri to get from the server, remember leading "/"!
|
||||
* @param settings connection settings (callbacks, proxy, etc.)
|
||||
* @param callback_arg argument passed to all the callbacks
|
||||
* @param connection retreives the connection handle (to match in callbacks)
|
||||
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
|
||||
* or an error code
|
||||
*/
|
||||
err_t
|
||||
httpc_get_file_to_disk(const ip_addr_t* server_addr, u16_t port, const char* uri, const httpc_connection_t *settings,
|
||||
void* callback_arg, const char* local_file_name, httpc_state_t **connection)
|
||||
{
|
||||
err_t err;
|
||||
httpc_state_t* req;
|
||||
httpc_filestate_t *filestate;
|
||||
|
||||
LWIP_ERROR("invalid parameters", (server_addr != NULL) && (uri != NULL) && (local_file_name != NULL), return ERR_ARG;);
|
||||
|
||||
err = httpc_fs_init(&filestate, local_file_name, settings, callback_arg);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpc_init_connection_addr(&req, &filestate->settings, server_addr, port,
|
||||
uri, httpc_fs_tcp_recv, filestate);
|
||||
if (err != ERR_OK) {
|
||||
httpc_fs_free(filestate);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (settings->use_proxy) {
|
||||
err = httpc_get_internal_addr(req, &settings->proxy_addr);
|
||||
} else {
|
||||
err = httpc_get_internal_addr(req, server_addr);
|
||||
}
|
||||
if(err != ERR_OK) {
|
||||
httpc_fs_free(filestate);
|
||||
httpc_free_state(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (connection != NULL) {
|
||||
*connection = req;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup httpc
|
||||
* HTTP client API: get a file to disk by passing server name as string (DNS name or IP address string)
|
||||
*
|
||||
* @param server_name server name as string (DNS name or IP address string)
|
||||
* @param port tcp port of the server
|
||||
* @param uri uri to get from the server, remember leading "/"!
|
||||
* @param settings connection settings (callbacks, proxy, etc.)
|
||||
* @param callback_arg argument passed to all the callbacks
|
||||
* @param connection retreives the connection handle (to match in callbacks)
|
||||
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
|
||||
* or an error code
|
||||
*/
|
||||
err_t
|
||||
httpc_get_file_dns_to_disk(const char* server_name, u16_t port, const char* uri, const httpc_connection_t *settings,
|
||||
void* callback_arg, const char* local_file_name, httpc_state_t **connection)
|
||||
{
|
||||
err_t err;
|
||||
httpc_state_t* req;
|
||||
httpc_filestate_t *filestate;
|
||||
|
||||
LWIP_ERROR("invalid parameters", (server_name != NULL) && (uri != NULL) && (local_file_name != NULL), return ERR_ARG;);
|
||||
|
||||
err = httpc_fs_init(&filestate, local_file_name, settings, callback_arg);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpc_init_connection(&req, &filestate->settings, server_name, port,
|
||||
uri, httpc_fs_tcp_recv, filestate);
|
||||
if (err != ERR_OK) {
|
||||
httpc_fs_free(filestate);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (settings->use_proxy) {
|
||||
err = httpc_get_internal_addr(req, &settings->proxy_addr);
|
||||
} else {
|
||||
err = httpc_get_internal_dns(req, server_name);
|
||||
}
|
||||
if(err != ERR_OK) {
|
||||
httpc_fs_free(filestate);
|
||||
httpc_free_state(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (connection != NULL) {
|
||||
*connection = req;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* LWIP_HTTPC_HAVE_FILE_IO */
|
||||
|
||||
#endif /* LWIP_TCP && LWIP_CALLBACK_API */
|
2762
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/httpd.c
Normal file
2762
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/httpd.c
Normal file
File diff suppressed because it is too large
Load Diff
123
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/httpd_structs.h
Normal file
123
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/httpd_structs.h
Normal file
@ -0,0 +1,123 @@
|
||||
#ifndef LWIP_HTTPD_STRUCTS_H
|
||||
#define LWIP_HTTPD_STRUCTS_H
|
||||
|
||||
#include "lwip/apps/httpd.h"
|
||||
|
||||
#if LWIP_HTTPD_DYNAMIC_HEADERS
|
||||
/** This struct is used for a list of HTTP header strings for various
|
||||
* filename extensions. */
|
||||
typedef struct {
|
||||
const char *extension;
|
||||
const char *content_type;
|
||||
} tHTTPHeader;
|
||||
|
||||
/** A list of strings used in HTTP headers (see RFC 1945 HTTP/1.0 and
|
||||
* RFC 2616 HTTP/1.1 for header field definitions) */
|
||||
static const char *const g_psHTTPHeaderStrings[] = {
|
||||
"HTTP/1.0 200 OK\r\n",
|
||||
"HTTP/1.0 404 File not found\r\n",
|
||||
"HTTP/1.0 400 Bad Request\r\n",
|
||||
"HTTP/1.0 501 Not Implemented\r\n",
|
||||
"HTTP/1.1 200 OK\r\n",
|
||||
"HTTP/1.1 404 File not found\r\n",
|
||||
"HTTP/1.1 400 Bad Request\r\n",
|
||||
"HTTP/1.1 501 Not Implemented\r\n",
|
||||
"Content-Length: ",
|
||||
"Connection: Close\r\n",
|
||||
"Connection: keep-alive\r\n",
|
||||
"Connection: keep-alive\r\nContent-Length: ",
|
||||
"Server: "HTTPD_SERVER_AGENT"\r\n",
|
||||
"\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
|
||||
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
|
||||
, "Connection: keep-alive\r\nContent-Length: 77\r\n\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Indexes into the g_psHTTPHeaderStrings array */
|
||||
#define HTTP_HDR_OK 0 /* 200 OK */
|
||||
#define HTTP_HDR_NOT_FOUND 1 /* 404 File not found */
|
||||
#define HTTP_HDR_BAD_REQUEST 2 /* 400 Bad request */
|
||||
#define HTTP_HDR_NOT_IMPL 3 /* 501 Not Implemented */
|
||||
#define HTTP_HDR_OK_11 4 /* 200 OK */
|
||||
#define HTTP_HDR_NOT_FOUND_11 5 /* 404 File not found */
|
||||
#define HTTP_HDR_BAD_REQUEST_11 6 /* 400 Bad request */
|
||||
#define HTTP_HDR_NOT_IMPL_11 7 /* 501 Not Implemented */
|
||||
#define HTTP_HDR_CONTENT_LENGTH 8 /* Content-Length: (HTTP 1.0)*/
|
||||
#define HTTP_HDR_CONN_CLOSE 9 /* Connection: Close (HTTP 1.1) */
|
||||
#define HTTP_HDR_CONN_KEEPALIVE 10 /* Connection: keep-alive (HTTP 1.1) */
|
||||
#define HTTP_HDR_KEEPALIVE_LEN 11 /* Connection: keep-alive + Content-Length: (HTTP 1.1)*/
|
||||
#define HTTP_HDR_SERVER 12 /* Server: HTTPD_SERVER_AGENT */
|
||||
#define DEFAULT_404_HTML 13 /* default 404 body */
|
||||
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
|
||||
#define DEFAULT_404_HTML_PERSISTENT 14 /* default 404 body, but including Connection: keep-alive */
|
||||
#endif
|
||||
|
||||
#define HTTP_CONTENT_TYPE(contenttype) "Content-Type: "contenttype"\r\n\r\n"
|
||||
#define HTTP_CONTENT_TYPE_ENCODING(contenttype, encoding) "Content-Type: "contenttype"\r\nContent-Encoding: "encoding"\r\n\r\n"
|
||||
|
||||
#define HTTP_HDR_HTML HTTP_CONTENT_TYPE("text/html")
|
||||
#define HTTP_HDR_SSI HTTP_CONTENT_TYPE("text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache")
|
||||
#define HTTP_HDR_GIF HTTP_CONTENT_TYPE("image/gif")
|
||||
#define HTTP_HDR_PNG HTTP_CONTENT_TYPE("image/png")
|
||||
#define HTTP_HDR_JPG HTTP_CONTENT_TYPE("image/jpeg")
|
||||
#define HTTP_HDR_BMP HTTP_CONTENT_TYPE("image/bmp")
|
||||
#define HTTP_HDR_ICO HTTP_CONTENT_TYPE("image/x-icon")
|
||||
#define HTTP_HDR_APP HTTP_CONTENT_TYPE("application/octet-stream")
|
||||
#define HTTP_HDR_JS HTTP_CONTENT_TYPE("application/javascript")
|
||||
#define HTTP_HDR_RA HTTP_CONTENT_TYPE("application/javascript")
|
||||
#define HTTP_HDR_CSS HTTP_CONTENT_TYPE("text/css")
|
||||
#define HTTP_HDR_SWF HTTP_CONTENT_TYPE("application/x-shockwave-flash")
|
||||
#define HTTP_HDR_XML HTTP_CONTENT_TYPE("text/xml")
|
||||
#define HTTP_HDR_PDF HTTP_CONTENT_TYPE("application/pdf")
|
||||
#define HTTP_HDR_JSON HTTP_CONTENT_TYPE("application/json")
|
||||
#define HTTP_HDR_CSV HTTP_CONTENT_TYPE("text/csv")
|
||||
#define HTTP_HDR_TSV HTTP_CONTENT_TYPE("text/tsv")
|
||||
#define HTTP_HDR_SVG HTTP_CONTENT_TYPE("image/svg+xml")
|
||||
#define HTTP_HDR_SVGZ HTTP_CONTENT_TYPE_ENCODING("image/svg+xml", "gzip")
|
||||
|
||||
#define HTTP_HDR_DEFAULT_TYPE HTTP_CONTENT_TYPE("text/plain")
|
||||
|
||||
/** A list of extension-to-HTTP header strings (see outdated RFC 1700 MEDIA TYPES
|
||||
* and http://www.iana.org/assignments/media-types for registered content types
|
||||
* and subtypes) */
|
||||
static const tHTTPHeader g_psHTTPHeaders[] = {
|
||||
{ "html", HTTP_HDR_HTML},
|
||||
{ "htm", HTTP_HDR_HTML},
|
||||
{ "shtml", HTTP_HDR_SSI},
|
||||
{ "shtm", HTTP_HDR_SSI},
|
||||
{ "ssi", HTTP_HDR_SSI},
|
||||
{ "gif", HTTP_HDR_GIF},
|
||||
{ "png", HTTP_HDR_PNG},
|
||||
{ "jpg", HTTP_HDR_JPG},
|
||||
{ "bmp", HTTP_HDR_BMP},
|
||||
{ "ico", HTTP_HDR_ICO},
|
||||
{ "class", HTTP_HDR_APP},
|
||||
{ "cls", HTTP_HDR_APP},
|
||||
{ "js", HTTP_HDR_JS},
|
||||
{ "ram", HTTP_HDR_RA},
|
||||
{ "css", HTTP_HDR_CSS},
|
||||
{ "swf", HTTP_HDR_SWF},
|
||||
{ "xml", HTTP_HDR_XML},
|
||||
{ "xsl", HTTP_HDR_XML},
|
||||
{ "pdf", HTTP_HDR_PDF},
|
||||
{ "json", HTTP_HDR_JSON}
|
||||
#ifdef HTTPD_ADDITIONAL_CONTENT_TYPES
|
||||
/* If you need to add content types not listed here:
|
||||
* #define HTTPD_ADDITIONAL_CONTENT_TYPES {"ct1", HTTP_CONTENT_TYPE("text/ct1")}, {"exe", HTTP_CONTENT_TYPE("application/exe")}
|
||||
*/
|
||||
, HTTPD_ADDITIONAL_CONTENT_TYPES
|
||||
#endif
|
||||
};
|
||||
|
||||
#define NUM_HTTP_HEADERS LWIP_ARRAYSIZE(g_psHTTPHeaders)
|
||||
|
||||
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
|
||||
|
||||
#if LWIP_HTTPD_SSI
|
||||
static const char *const g_pcSSIExtensions[] = {
|
||||
".shtml", ".shtm", ".ssi", ".xml", ".json"
|
||||
};
|
||||
#define NUM_SHTML_EXTENSIONS LWIP_ARRAYSIZE(g_pcSSIExtensions)
|
||||
#endif /* LWIP_HTTPD_SSI */
|
||||
|
||||
#endif /* LWIP_HTTPD_STRUCTS_H */
|
@ -0,0 +1,97 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
open(OUTPUT, "> fsdata.c");
|
||||
|
||||
chdir("fs");
|
||||
open(FILES, "find . -type f |");
|
||||
|
||||
while($file = <FILES>) {
|
||||
|
||||
# Do not include files in CVS directories nor backup files.
|
||||
if($file =~ /(CVS|~)/) {
|
||||
next;
|
||||
}
|
||||
|
||||
chop($file);
|
||||
|
||||
open(HEADER, "> /tmp/header") || die $!;
|
||||
if($file =~ /404/) {
|
||||
print(HEADER "HTTP/1.0 404 File not found\r\n");
|
||||
} else {
|
||||
print(HEADER "HTTP/1.0 200 OK\r\n");
|
||||
}
|
||||
print(HEADER "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n");
|
||||
if($file =~ /\.html$/) {
|
||||
print(HEADER "Content-type: text/html\r\n");
|
||||
} elsif($file =~ /\.gif$/) {
|
||||
print(HEADER "Content-type: image/gif\r\n");
|
||||
} elsif($file =~ /\.png$/) {
|
||||
print(HEADER "Content-type: image/png\r\n");
|
||||
} elsif($file =~ /\.jpg$/) {
|
||||
print(HEADER "Content-type: image/jpeg\r\n");
|
||||
} elsif($file =~ /\.class$/) {
|
||||
print(HEADER "Content-type: application/octet-stream\r\n");
|
||||
} elsif($file =~ /\.ram$/) {
|
||||
print(HEADER "Content-type: audio/x-pn-realaudio\r\n");
|
||||
} else {
|
||||
print(HEADER "Content-type: text/plain\r\n");
|
||||
}
|
||||
print(HEADER "\r\n");
|
||||
close(HEADER);
|
||||
|
||||
unless($file =~ /\.plain$/ || $file =~ /cgi/) {
|
||||
system("cat /tmp/header $file > /tmp/file");
|
||||
} else {
|
||||
system("cp $file /tmp/file");
|
||||
}
|
||||
|
||||
open(FILE, "/tmp/file");
|
||||
unlink("/tmp/file");
|
||||
unlink("/tmp/header");
|
||||
|
||||
$file =~ s/\.//;
|
||||
$fvar = $file;
|
||||
$fvar =~ s-/-_-g;
|
||||
$fvar =~ s-\.-_-g;
|
||||
print(OUTPUT "static const unsigned char data".$fvar."[] = {\n");
|
||||
print(OUTPUT "\t/* $file */\n\t");
|
||||
for($j = 0; $j < length($file); $j++) {
|
||||
printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1)));
|
||||
}
|
||||
printf(OUTPUT "0,\n");
|
||||
|
||||
|
||||
$i = 0;
|
||||
while(read(FILE, $data, 1)) {
|
||||
if($i == 0) {
|
||||
print(OUTPUT "\t");
|
||||
}
|
||||
printf(OUTPUT "%#02x, ", unpack("C", $data));
|
||||
$i++;
|
||||
if($i == 10) {
|
||||
print(OUTPUT "\n");
|
||||
$i = 0;
|
||||
}
|
||||
}
|
||||
print(OUTPUT "};\n\n");
|
||||
close(FILE);
|
||||
push(@fvars, $fvar);
|
||||
push(@files, $file);
|
||||
}
|
||||
|
||||
for($i = 0; $i < @fvars; $i++) {
|
||||
$file = $files[$i];
|
||||
$fvar = $fvars[$i];
|
||||
|
||||
if($i == 0) {
|
||||
$prevfile = "NULL";
|
||||
} else {
|
||||
$prevfile = "file" . $fvars[$i - 1];
|
||||
}
|
||||
print(OUTPUT "const struct fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, ");
|
||||
print(OUTPUT "data$fvar + ". (length($file) + 1) .", ");
|
||||
print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n");
|
||||
}
|
||||
|
||||
print(OUTPUT "#define FS_ROOT file$fvars[$i - 1]\n\n");
|
||||
print(OUTPUT "#define FS_NUMFILES $i\n");
|
1251
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/makefsdata/makefsdata.c
Normal file
1251
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/makefsdata/makefsdata.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,13 @@
|
||||
This directory contains a script ('makefsdata') to create C code suitable for
|
||||
httpd for given html pages (or other files) in a directory.
|
||||
|
||||
There is also a plain C console application doing the same and extended a bit.
|
||||
|
||||
Usage: htmlgen [targetdir] [-s] [-i]s
|
||||
targetdir: relative or absolute path to files to convert
|
||||
switch -s: toggle processing of subdirectories (default is on)
|
||||
switch -e: exclude HTTP header from file (header is created at runtime, default is on)
|
||||
switch -11: include HTTP 1.1 header (1.0 is default)
|
||||
|
||||
if targetdir not specified, makefsdata will attempt to
|
||||
process files in subdirectory 'fs'.
|
808
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/makefsdata/tinydir.h
Normal file
808
MXC_A27-PCB4.5-270T/lib/lwip/src/apps/http/makefsdata/tinydir.h
Normal file
@ -0,0 +1,808 @@
|
||||
/*
|
||||
Copyright (c) 2013-2017, tinydir authors:
|
||||
- Cong Xu
|
||||
- Lautis Sun
|
||||
- Baudouin Feildel
|
||||
- Andargor <andargor@yahoo.com>
|
||||
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 OWNER 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 TINYDIR_H
|
||||
#define TINYDIR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if ((defined _UNICODE) && !(defined UNICODE))
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#if ((defined UNICODE) && !(defined _UNICODE))
|
||||
#define _UNICODE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef _MSC_VER
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# pragma warning(push)
|
||||
# pragma warning (disable : 4996)
|
||||
#else
|
||||
# include <dirent.h>
|
||||
# include <libgen.h>
|
||||
# include <sys/stat.h>
|
||||
# include <stddef.h>
|
||||
#endif
|
||||
#ifdef __MINGW32__
|
||||
# include <tchar.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* types */
|
||||
|
||||
/* Windows UNICODE wide character support */
|
||||
#if defined _MSC_VER || defined __MINGW32__
|
||||
#define _tinydir_char_t TCHAR
|
||||
#define TINYDIR_STRING(s) _TEXT(s)
|
||||
#define _tinydir_strlen _tcslen
|
||||
#define _tinydir_strcpy _tcscpy
|
||||
#define _tinydir_strcat _tcscat
|
||||
#define _tinydir_strcmp _tcscmp
|
||||
#define _tinydir_strrchr _tcsrchr
|
||||
#define _tinydir_strncmp _tcsncmp
|
||||
#else
|
||||
#define _tinydir_char_t char
|
||||
#define TINYDIR_STRING(s) s
|
||||
#define _tinydir_strlen strlen
|
||||
#define _tinydir_strcpy strcpy
|
||||
#define _tinydir_strcat strcat
|
||||
#define _tinydir_strcmp strcmp
|
||||
#define _tinydir_strrchr strrchr
|
||||
#define _tinydir_strncmp strncmp
|
||||
#endif
|
||||
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
#include <windows.h>
|
||||
#define _TINYDIR_PATH_MAX MAX_PATH
|
||||
#elif defined __linux__
|
||||
#include <linux/limits.h>
|
||||
#define _TINYDIR_PATH_MAX PATH_MAX
|
||||
#else
|
||||
#define _TINYDIR_PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* extra chars for the "\\*" mask */
|
||||
# define _TINYDIR_PATH_EXTRA 2
|
||||
#else
|
||||
# define _TINYDIR_PATH_EXTRA 0
|
||||
#endif
|
||||
|
||||
#define _TINYDIR_FILENAME_MAX 256
|
||||
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
#define _TINYDIR_DRIVE_MAX 3
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define _TINYDIR_FUNC static __inline
|
||||
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
||||
# define _TINYDIR_FUNC static __inline__
|
||||
#else
|
||||
# define _TINYDIR_FUNC static inline
|
||||
#endif
|
||||
|
||||
/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
|
||||
#ifdef TINYDIR_USE_READDIR_R
|
||||
|
||||
/* readdir_r is a POSIX-only function, and may not be available under various
|
||||
* environments/settings, e.g. MinGW. Use readdir fallback */
|
||||
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
|
||||
_POSIX_SOURCE
|
||||
# define _TINYDIR_HAS_READDIR_R
|
||||
#endif
|
||||
#if _POSIX_C_SOURCE >= 200112L
|
||||
# define _TINYDIR_HAS_FPATHCONF
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#if _BSD_SOURCE || _SVID_SOURCE || \
|
||||
(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
|
||||
# define _TINYDIR_HAS_DIRFD
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
|
||||
defined _PC_NAME_MAX
|
||||
# define _TINYDIR_USE_FPATHCONF
|
||||
#endif
|
||||
#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
|
||||
!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
|
||||
# define _TINYDIR_USE_READDIR
|
||||
#endif
|
||||
|
||||
/* Use readdir by default */
|
||||
#else
|
||||
# define _TINYDIR_USE_READDIR
|
||||
#endif
|
||||
|
||||
/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
|
||||
#ifndef _MSC_VER
|
||||
#if (defined __MINGW32__) && (defined _UNICODE)
|
||||
#define _TINYDIR_DIR _WDIR
|
||||
#define _tinydir_dirent _wdirent
|
||||
#define _tinydir_opendir _wopendir
|
||||
#define _tinydir_readdir _wreaddir
|
||||
#define _tinydir_closedir _wclosedir
|
||||
#else
|
||||
#define _TINYDIR_DIR DIR
|
||||
#define _tinydir_dirent dirent
|
||||
#define _tinydir_opendir opendir
|
||||
#define _tinydir_readdir readdir
|
||||
#define _tinydir_closedir closedir
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
|
||||
#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
|
||||
#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
|
||||
#else
|
||||
#error "Either define both alloc and free or none of them!"
|
||||
#endif
|
||||
|
||||
#if !defined(_TINYDIR_MALLOC)
|
||||
#define _TINYDIR_MALLOC(_size) malloc(_size)
|
||||
#define _TINYDIR_FREE(_ptr) free(_ptr)
|
||||
#endif /* !defined(_TINYDIR_MALLOC) */
|
||||
|
||||
typedef struct tinydir_file
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
|
||||
_tinydir_char_t *extension;
|
||||
int is_dir;
|
||||
int is_reg;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifdef __MINGW32__
|
||||
struct _stat _s;
|
||||
#else
|
||||
struct stat _s;
|
||||
#endif
|
||||
#endif
|
||||
} tinydir_file;
|
||||
|
||||
typedef struct tinydir_dir
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
int has_next;
|
||||
size_t n_files;
|
||||
|
||||
tinydir_file *_files;
|
||||
#ifdef _MSC_VER
|
||||
HANDLE _h;
|
||||
WIN32_FIND_DATA _f;
|
||||
#else
|
||||
_TINYDIR_DIR *_d;
|
||||
struct _tinydir_dirent *_e;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
struct _tinydir_dirent *_ep;
|
||||
#endif
|
||||
#endif
|
||||
} tinydir_dir;
|
||||
|
||||
|
||||
/* declarations */
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
void tinydir_close(tinydir_dir *dir);
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_next(tinydir_dir *dir);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
void _tinydir_get_ext(tinydir_file *file);
|
||||
_TINYDIR_FUNC
|
||||
int _tinydir_file_cmp(const void *a, const void *b);
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
_TINYDIR_FUNC
|
||||
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* definitions*/
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
int error;
|
||||
int size; /* using int size */
|
||||
#endif
|
||||
#else
|
||||
_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
|
||||
#endif
|
||||
_tinydir_char_t *pathp;
|
||||
|
||||
if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* initialise dir */
|
||||
dir->_files = NULL;
|
||||
#ifdef _MSC_VER
|
||||
dir->_h = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
dir->_d = NULL;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
dir->_ep = NULL;
|
||||
#endif
|
||||
#endif
|
||||
tinydir_close(dir);
|
||||
|
||||
_tinydir_strcpy(dir->path, path);
|
||||
/* Remove trailing slashes */
|
||||
pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
|
||||
while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
|
||||
{
|
||||
*pathp = TINYDIR_STRING('\0');
|
||||
pathp++;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
_tinydir_strcpy(path_buf, dir->path);
|
||||
_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
|
||||
#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
|
||||
dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
|
||||
#else
|
||||
dir->_h = FindFirstFile(path_buf, &dir->_f);
|
||||
#endif
|
||||
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errno = ENOENT;
|
||||
#else
|
||||
dir->_d = _tinydir_opendir(path);
|
||||
if (dir->_d == NULL)
|
||||
{
|
||||
#endif
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* read first file */
|
||||
dir->has_next = 1;
|
||||
#ifndef _MSC_VER
|
||||
#ifdef _TINYDIR_USE_READDIR
|
||||
dir->_e = _tinydir_readdir(dir->_d);
|
||||
#else
|
||||
/* allocate dirent buffer for readdir_r */
|
||||
size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
|
||||
if (size == -1) return -1;
|
||||
dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
|
||||
if (dir->_ep == NULL) return -1;
|
||||
|
||||
error = readdir_r(dir->_d, dir->_ep, &dir->_e);
|
||||
if (error != 0) return -1;
|
||||
#endif
|
||||
if (dir->_e == NULL)
|
||||
{
|
||||
dir->has_next = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
tinydir_close(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||
{
|
||||
/* Count the number of files first, to pre-allocate the files array */
|
||||
size_t n_files = 0;
|
||||
if (tinydir_open(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
while (dir->has_next)
|
||||
{
|
||||
n_files++;
|
||||
if (tinydir_next(dir) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
tinydir_close(dir);
|
||||
|
||||
if (tinydir_open(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir->n_files = 0;
|
||||
dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
|
||||
if (dir->_files == NULL)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
while (dir->has_next)
|
||||
{
|
||||
tinydir_file *p_file;
|
||||
dir->n_files++;
|
||||
|
||||
p_file = &dir->_files[dir->n_files - 1];
|
||||
if (tinydir_readfile(dir, p_file) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (tinydir_next(dir) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Just in case the number of files has changed between the first and
|
||||
second reads, terminate without writing into unallocated memory */
|
||||
if (dir->n_files == n_files)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
tinydir_close(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
void tinydir_close(tinydir_dir *dir)
|
||||
{
|
||||
if (dir == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(dir->path, 0, sizeof(dir->path));
|
||||
dir->has_next = 0;
|
||||
dir->n_files = 0;
|
||||
_TINYDIR_FREE(dir->_files);
|
||||
dir->_files = NULL;
|
||||
#ifdef _MSC_VER
|
||||
if (dir->_h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FindClose(dir->_h);
|
||||
}
|
||||
dir->_h = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
if (dir->_d)
|
||||
{
|
||||
_tinydir_closedir(dir->_d);
|
||||
}
|
||||
dir->_d = NULL;
|
||||
dir->_e = NULL;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
_TINYDIR_FREE(dir->_ep);
|
||||
dir->_ep = NULL;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_next(tinydir_dir *dir)
|
||||
{
|
||||
if (dir == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!dir->has_next)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
if (FindNextFile(dir->_h, &dir->_f) == 0)
|
||||
#else
|
||||
#ifdef _TINYDIR_USE_READDIR
|
||||
dir->_e = _tinydir_readdir(dir->_d);
|
||||
#else
|
||||
if (dir->_ep == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
if (dir->_e == NULL)
|
||||
#endif
|
||||
{
|
||||
dir->has_next = 0;
|
||||
#ifdef _MSC_VER
|
||||
if (GetLastError() != ERROR_SUCCESS &&
|
||||
GetLastError() != ERROR_NO_MORE_FILES)
|
||||
{
|
||||
tinydir_close(dir);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
|
||||
{
|
||||
if (dir == NULL || file == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||
#else
|
||||
if (dir->_e == NULL)
|
||||
#endif
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(dir->path) +
|
||||
_tinydir_strlen(
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
) + 1 + _TINYDIR_PATH_EXTRA >=
|
||||
_TINYDIR_PATH_MAX)
|
||||
{
|
||||
/* the path for the file will be too long */
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
) >= _TINYDIR_FILENAME_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_tinydir_strcpy(file->path, dir->path);
|
||||
_tinydir_strcat(file->path, TINYDIR_STRING("/"));
|
||||
_tinydir_strcpy(file->name,
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
);
|
||||
_tinydir_strcat(file->path, file->name);
|
||||
#ifndef _MSC_VER
|
||||
#ifdef __MINGW32__
|
||||
if (_tstat(
|
||||
#else
|
||||
if (stat(
|
||||
#endif
|
||||
file->path, &file->_s) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
_tinydir_get_ext(file);
|
||||
|
||||
file->is_dir =
|
||||
#ifdef _MSC_VER
|
||||
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
S_ISDIR(file->_s.st_mode);
|
||||
#endif
|
||||
file->is_reg =
|
||||
#ifdef _MSC_VER
|
||||
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
|
||||
(
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
|
||||
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
|
||||
#endif
|
||||
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
|
||||
#endif
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
|
||||
#else
|
||||
S_ISREG(file->_s.st_mode);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
|
||||
{
|
||||
if (dir == NULL || file == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (i >= dir->n_files)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(file, &dir->_files[i], sizeof(tinydir_file));
|
||||
_tinydir_get_ext(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
if (dir == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (i >= dir->n_files || !dir->_files[i].is_dir)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_tinydir_strcpy(path, dir->_files[i].path);
|
||||
tinydir_close(dir);
|
||||
if (tinydir_open_sorted(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open a single file given its path */
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
|
||||
{
|
||||
tinydir_dir dir;
|
||||
int result = 0;
|
||||
int found = 0;
|
||||
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
|
||||
_tinydir_char_t *dir_name;
|
||||
_tinydir_char_t *base_name;
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
|
||||
#endif
|
||||
|
||||
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the parent path */
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
|
||||
_tsplitpath_s(
|
||||
path,
|
||||
drive_buf, _TINYDIR_DRIVE_MAX,
|
||||
dir_name_buf, _TINYDIR_FILENAME_MAX,
|
||||
file_name_buf, _TINYDIR_FILENAME_MAX,
|
||||
ext_buf, _TINYDIR_FILENAME_MAX);
|
||||
#else
|
||||
_tsplitpath(
|
||||
path,
|
||||
drive_buf,
|
||||
dir_name_buf,
|
||||
file_name_buf,
|
||||
ext_buf);
|
||||
#endif
|
||||
|
||||
/* _splitpath_s not work fine with only filename and widechar support */
|
||||
#ifdef _UNICODE
|
||||
if (drive_buf[0] == L'\xFEFE')
|
||||
drive_buf[0] = '\0';
|
||||
if (dir_name_buf[0] == L'\xFEFE')
|
||||
dir_name_buf[0] = '\0';
|
||||
#endif
|
||||
|
||||
if (errno)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Emulate the behavior of dirname by returning "." for dir name if it's
|
||||
empty */
|
||||
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
|
||||
{
|
||||
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
|
||||
}
|
||||
/* Concatenate the drive letter and dir name to form full dir name */
|
||||
_tinydir_strcat(drive_buf, dir_name_buf);
|
||||
dir_name = drive_buf;
|
||||
/* Concatenate the file name and extension to form base name */
|
||||
_tinydir_strcat(file_name_buf, ext_buf);
|
||||
base_name = file_name_buf;
|
||||
#else
|
||||
_tinydir_strcpy(dir_name_buf, path);
|
||||
dir_name = dirname(dir_name_buf);
|
||||
_tinydir_strcpy(file_name_buf, path);
|
||||
base_name =basename(file_name_buf);
|
||||
#endif
|
||||
|
||||
/* Open the parent directory */
|
||||
if (tinydir_open(&dir, dir_name) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read through the parent directory and look for the file */
|
||||
while (dir.has_next)
|
||||
{
|
||||
if (tinydir_readfile(&dir, file) == -1)
|
||||
{
|
||||
result = -1;
|
||||
goto bail;
|
||||
}
|
||||
if (_tinydir_strcmp(file->name, base_name) == 0)
|
||||
{
|
||||
/* File found */
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
tinydir_next(&dir);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
result = -1;
|
||||
errno = ENOENT;
|
||||
}
|
||||
|
||||
bail:
|
||||
tinydir_close(&dir);
|
||||
return result;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
void _tinydir_get_ext(tinydir_file *file)
|
||||
{
|
||||
_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
|
||||
if (period == NULL)
|
||||
{
|
||||
file->extension = &(file->name[_tinydir_strlen(file->name)]);
|
||||
}
|
||||
else
|
||||
{
|
||||
file->extension = period + 1;
|
||||
}
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int _tinydir_file_cmp(const void *a, const void *b)
|
||||
{
|
||||
const tinydir_file *fa = (const tinydir_file *)a;
|
||||
const tinydir_file *fb = (const tinydir_file *)b;
|
||||
if (fa->is_dir != fb->is_dir)
|
||||
{
|
||||
return -(fa->is_dir - fb->is_dir);
|
||||
}
|
||||
return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
/*
|
||||
The following authored by Ben Hutchings <ben@decadent.org.uk>
|
||||
from https://womble.decadent.org.uk/readdir_r-advisory.html
|
||||
*/
|
||||
/* Calculate the required buffer size (in bytes) for directory *
|
||||
* entries read from the given directory handle. Return -1 if this *
|
||||
* this cannot be done. *
|
||||
* *
|
||||
* This code does not trust values of NAME_MAX that are less than *
|
||||
* 255, since some systems (including at least HP-UX) incorrectly *
|
||||
* define it to be a smaller value. */
|
||||
_TINYDIR_FUNC
|
||||
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
|
||||
{
|
||||
long name_max;
|
||||
size_t name_end;
|
||||
/* parameter may be unused */
|
||||
(void)dirp;
|
||||
|
||||
#if defined _TINYDIR_USE_FPATHCONF
|
||||
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
|
||||
if (name_max == -1)
|
||||
#if defined(NAME_MAX)
|
||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||
#else
|
||||
return (size_t)(-1);
|
||||
#endif
|
||||
#elif defined(NAME_MAX)
|
||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||
#else
|
||||
#error "buffer size for readdir_r cannot be determined"
|
||||
#endif
|
||||
name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
|
||||
return (name_end > sizeof(struct _tinydir_dirent) ?
|
||||
name_end : sizeof(struct _tinydir_dirent));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
# if defined (_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user