Goto sanos source index

//
// hutils.c
//
// HTTP utility routines
//
// Copyright (C) 2002 Michael Ringgaard. 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. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission. 
// 
// 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.
// 

#include <os.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <inifile.h>

static const char hex[] = "0123456789abcdef";

char *getstrconfig(struct section *cfg, char *name, char *defval) {
  char *val;

  if (!cfg) return defval;
  val = find_property(cfg, name);
  if (!val) return defval;
  return val;
}

int getnumconfig(struct section *cfg, char *name, int defval) {
  char *val;

  if (!cfg) return defval;
  val = find_property(cfg, name);
  if (!val) return defval;
  return atoi(val);
}

static int hexdigit(int x) {
  return (x <= '9') ? x - '0' : (x & 7) + 9;
}

int decode_url(char *from, char *to) {
  char c, x1, x2;

  while ((c = *from++) != 0) {
    if (c == '%') {
      x1 = *from++;
      if (!isxdigit(x1)) {
        errno = EINVAL;
        return -1;
      }
      x2 = *from++;
      if (!isxdigit(x2)) {
        errno = EINVAL;
        return -1;
      }
      if (x1 == 0 && x2 == 0) {
        errno = EINVAL;
        return -1;
      }
      *to++ = (hexdigit(x1) << 4) + hexdigit(x2);
    } else {
      *to++ = c;
    }
  }

  *to = 0;
  return 0;
}

void encode_url(const char *from, char *to) {
  char c;

  while ((c = *from++) != 0) {
    switch (c) {
      case '%':
      case ' ':
      case '?':
      case '+':
      case '&':
        *to++ = '%';
        *to++ = hex[(c >> 4) & 15];
        *to++ = hex[c & 15];
        break;

      default:
        *to++ = c;
        break;
    }
  }
  *to = 0;
}

time_t timerfc(char *s) {
  struct tm tm;
  char month[3];
  char c;
  unsigned n;
  char flag;
  char state;
  char isctime;
  enum { D_START, D_END, D_MON, D_DAY, D_YEAR, D_HOUR, D_MIN, D_SEC };

  tm.tm_sec = 60;
  tm.tm_min = 60;
  tm.tm_hour = 24;
  tm.tm_mday = 32;
  tm.tm_year = 1969;
  isctime = 0;
  month[0] = 0;
  state = D_START;
  n = 0;
  flag = 1;
  while (*s && state != D_END) {
    c = *s++;
    switch (state) {
      case D_START:
        if (c == ' ') {
          state = D_MON;
          isctime = 1;
        } else if (c == ',') {
          state = D_DAY;
        }
        break;

      case D_MON:
        if (isalpha(c)) {
          if (n < 3) month[n++] = c;
        } else {
          if (n < 3) return -1;
          n = 0;
          state = isctime ? D_DAY : D_YEAR;
        }
        break;

      case D_DAY:
        if (c == ' ' && flag) {
        } else if (isdigit(c)) {
          flag = 0;
          n = 10 * n + (c - '0');
        } else {
          tm.tm_mday = n;
          n = 0;
          state = isctime ? D_HOUR : D_MON;
        }
        break;

      case D_YEAR:
        if (isdigit(c)) {
          n = 10 * n + (c - '0');
        } else {
          tm.tm_year = n;
          n = 0;
          state = isctime ? D_END : D_HOUR;
        }
        break;

      case D_HOUR:
        if (isdigit(c)) {
          n = 10 * n + (c - '0');
        } else {
          tm.tm_hour = n;
          n = 0;
          state = D_MIN;
        }
        break;

      case D_MIN:
        if (isdigit(c)) {
          n = 10 * n + (c - '0');
        } else {
          tm.tm_min = n;
          n = 0;
          state = D_SEC;
        }
        break;

      case D_SEC:
        if (isdigit(c)) {
          n = 10 * n + (c - '0');
        } else {
          tm.tm_sec = n;
          n = 0;
          state = isctime ? D_YEAR : D_END;
        }
        break;
    }
  }

  switch (month[0]) {
    case 'A': tm.tm_mon = (month[1] == 'p') ? 4 : 8; break;
    case 'D': tm.tm_mon = 12; break;
    case 'F': tm.tm_mon = 2; break;
    case 'J': tm.tm_mon = (month[1] == 'a') ? 1 : ((month[2] == 'l') ? 7 : 6); break;
    case 'M': tm.tm_mon = (month[2] == 'r') ? 3 : 5; break;
    case 'N': tm.tm_mon = 11; break;
    case 'O': tm.tm_mon = 10; break;
    case 'S': tm.tm_mon = 9; break;
    default: return -1;
  }
  if (tm.tm_year <= 100) tm.tm_year += (tm.tm_year < 70) ? 2000 : 1900;

  tm.tm_year -= 1900;
  tm.tm_mon--;
  tm.tm_mday--;

  return mktime(&tm);
}

char *rfctime(time_t t, char *buf) {
  struct tm *tm;

  tm = gmtime(&t);
  if (!tm) return NULL;
  strftime(buf, 31, "%a, %d %b %Y %H:%M:%S GMT", tm);
  return buf;
}