Network Services

Dependents:   PwrCond_mbed5

Fork of W5500Interface_K22F by Andrew McCartney

HTTPD/HTTPD_util.cpp

Committer:
dgriffin65
Date:
2017-06-15
Revision:
15:14382459c8b7

File content as of revision 15:14382459c8b7:

/* Copyright (C) 2013 Hiroshi Suga, MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 * and associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "HTTPD.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#define MIMETABLE_NUM 9
static const struct {
    char ext[5];
    char type[24];
} mimetable[MIMETABLE_NUM] = {
    {"txt", "text/plain"},  // default
    {"html", "text/html"},
    {"htm", "text/html"},
    {"css", "text/css"},
    {"js",  "application/javascript"},
    {"jpg", "image/jpeg"},
    {"png", "image/png"},
    {"gif", "image/gif"},
    {"ico", "image/x-icon"},
};

char *HTTPD::getUri (int id) {
    return _state[id].uri;
}

char *HTTPD::getFilename (int id) {
    return _state[id].filename;
}

char *HTTPD::getQueryString (int id) {
    return _state[id].querystring;
}

int HTTPD::receive (int id, char *buf, int len) {
    int i;

    for (i = 0; i < len; i ++) {
        if (_state[id].buf->dequeue(&buf[i]) == false) break;
    }
    return i;
}

int HTTPD::send (int id, const char *body, int len, const char *header) {
    char buf[HTTPD_CMD_SIZE];

    strcpy(buf, "HTTP/1.1 200 OK\r\n");
    _state[id].client->send(buf, strlen(buf));
    strcpy(buf, "Server: GSwifi httpd\r\n");
    _state[id].client->send(buf, strlen(buf));
    if (_state[id].keepalive) {
        strcpy(buf, "Connection: Keep-Alive\r\n");
    } else {
        strcpy(buf, "Connection: close\r\n");
    }
    _state[id].client->send(buf, strlen(buf));
    if (header) {
        _state[id].client->send((char*)header, strlen(header));
    }
    sprintf(buf, "Content-Length: %d\r\n\r\n", len);
    _state[id].client->send(buf, strlen(buf));

    return _state[id].client->send((char*)body, len);
}

int HTTPD::sendstr (int id, const char *buf) {
    return _state[id].client->send((char*)buf, strlen(buf));
}


int HTTPD::hprintf(int id, const char* format, ...) {
    //FIX ME: This could result in memory overruns if the buffer size is exceeded
    static Mutex _mtx;
    static char  _buf[1024];

    std::va_list arg;
    
    _mtx.lock();
    
    va_start(arg, format);
    vsprintf(_buf, format, arg);
    va_end(arg);

    int r = _state[id].client->send(_buf, strlen(_buf));

    _mtx.unlock();
    return r;
}

int HTTPD::getHandler (const char *uri) {
    int i;

    for (i = 0; i < _handler_count; i ++) {
        if (strncmp(uri, _handler[i].uri, strlen(_handler[i].uri)) == NULL) {
            // found
            return i;
        }
    }
    return -1;
}

int HTTPD::attach (const char *uri, const char *dir) {
    if (_handler_count < HTTPD_MAX_HANDLES) {
        _handler[_handler_count].uri = (char*)malloc(strlen(uri) + 1);
        strcpy(_handler[_handler_count].uri, uri);
        _handler[_handler_count].dir = (char*)malloc(strlen(dir) + 1);
        strcpy(_handler[_handler_count].dir, dir);
        _handler[_handler_count].funcCgi = NULL;
        _handler_count ++;
        return 0;
    } else {
        return -1;
    }
}

int HTTPD::attach (const char *uri, void (*funcCgi)(int)) {
    if (_handler_count < HTTPD_MAX_HANDLES) {
        _handler[_handler_count].uri = (char*)malloc(strlen(uri) + 1);
        strcpy(_handler[_handler_count].uri, uri);
        _handler[_handler_count].dir = NULL;
        _handler[_handler_count].funcCgi = funcCgi;
        _handler_count ++;
        return 0;
    } else {
        return -1;
    }
}


char *HTTPD::mimetype (char *file) {
    int i, j;

    for (i = 0; i < MIMETABLE_NUM; i ++) {
        j = strlen(mimetable[i].ext);
        if (file[strlen(file) - j - 1] == '.' &&
          strnicmp(&file[strlen(file) - j], mimetable[i].ext, j) == NULL) {
            return (char*)mimetable[i].type;
        }
    }
    return (char*)mimetable[0].type;
}

int HTTPD::strnicmp (const char *p1, const char *p2, int n) {
    int i, r = -1;
    char c1, c2;
    
    for (i = 0; i < n; i ++) {
        c1 = (p1[i] >= 'a' && p1[i] <= 'z') ? p1[i] - ('a' - 'A'): p1[i];
        c2 = (p2[i] >= 'a' && p2[i] <= 'z') ? p2[i] - ('a' - 'A'): p2[i];
        r = c1 - c2;
        if (r) break;
    }
    return r;
}


/* base64encode code from 
 * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
 */
int HTTPD::base64encode (const char *input, int length, char *output, int len) {
    static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    unsigned int c, c1, c2, c3;
 
    if (len < ((((length-1)/3)+1)<<2)) return -1;
    for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) {
        c1 = ((((unsigned char)*((unsigned char *)&input[i]))));
        c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0;
        c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0;
 
        c = ((c1 & 0xFC) >> 2);
        output[j+0] = base64[c];
        c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4);
        output[j+1] = base64[c];
        c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6);
        output[j+2] = (length>i+1)?base64[c]:'=';
        c = (c3 & 0x3F);
        output[j+3] = (length>i+2)?base64[c]:'=';
    }
    output[(((length-1)/3)+1)<<2] = '\0';
    return 0;
}
 
 
/* urlencode code from 
 * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
 */
int HTTPD::urlencode (const char *str, char *buf, int len) {
//  char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf;
    const char *pstr = str;
    char *pbuf = buf;
 
    if (len < (strlen(str) * 3 + 1)) return -1;
    while (*pstr) {
        if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') 
            *pbuf++ = *pstr;
        else if (*pstr == ' ') 
            *pbuf++ = '+';
        else 
            *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
        pstr++;
    }
    *pbuf = '\0';
    return 0;
}
 
/* urldecode code from 
 * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
 */
int HTTPD::urldecode (const char *str, char *buf, int len) {
//  char *pstr = str, *buf = (char*)malloc(strlen(str) + 1), *pbuf = buf;
    const char *pstr = str;
    char *pbuf = buf;
 
    if (len < (strlen(str) / 3 - 1)) return -1;
    while (*pstr) {
        if (*pstr == '%') {
            if (pstr[1] && pstr[2]) {
                *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
                pstr += 2;
            }
        } else if (*pstr == '+') { 
            *pbuf++ = ' ';
        } else {
            *pbuf++ = *pstr;
        }
        pstr++;
    }
    *pbuf = '\0';
    return 0;
}

int HTTPD::from_hex (int ch) {
  return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
}
 
int HTTPD::to_hex (int code) {
  static char hex[] = "0123456789abcdef";
  return hex[code & 15];
}