Ejemplo n.º 1
0
/**
 * The poll function is called every 2nd second.
 * If there has been no data sent (which resets the retries) in 8 seconds, close.
 * If the last portion of a file has not been sent in 2 seconds, close.
 *
 * This could be increased, but we don't want to waste resources for bad connections.
 */
static err_t
http_poll(void *arg, struct tcp_pcb *pcb)
{
  struct http_state *hs = arg;
  LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: pcb=0x%08X hs=0x%08X pcb_state=%s\n",
    pcb, hs, tcp_debug_state_str(pcb->state)));
  
  if (hs == NULL) {
    if (pcb->state == ESTABLISHED) {
      /* arg is null, close. */
      LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: arg is NULL, close\n"));
      http_close_conn(pcb, hs);
      return ERR_ABRT;
    }
  } else {
    hs->retries++;
    if (hs->retries == HTTPD_MAX_RETRIES) {
      LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: too many retries, close\n"));
      http_close_conn(pcb, hs);
      return ERR_ABRT;
    }
    LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: try to send more data\n"));
    http_send_data(pcb, hs);
  }

  return ERR_OK;
}
Ejemplo n.º 2
0
/**
 * Data has been sent and acknowledged by the remote host.
 * This means that more data can be sent.
 */
static err_t
http_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
  struct http_state *hs = arg;
  LWIP_DEBUGF(HTTPD_DEBUG, ("http_sent: pcb=0x%08X hs=0x%08X len=%d\n", pcb, hs, len));

  LWIP_UNUSED_ARG(len);

  if (hs == NULL) {
    /* this should not happen, but just to be robust... */
    return ERR_OK;
  }
#if HTTPD_TRACK_SENT_BYTES
  hs->sent_total += len;
  LWIP_DEBUGF(HTTPD_DEBUG, ("http_sent: sent_total=%d, file size=%d\n", hs->sent_total, hs->file_size));
  if(hs->sent_total > hs->file_size) {
    LWIP_DEBUGF(HTTPD_DEBUG, ("http_sent: sent %d bytes too much!\n", hs->sent_total - hs->file_size));
  }
#endif /* HTTPD_TRACK_SENT_BYTES */

  /* reset retry counter */
  hs->retries = 0;
  
  if (hs->left > 0) {
    LWIP_DEBUGF(HTTPD_DEBUG, ("http_sent: %d bytes left, calling http_send_data\n", hs->left));
    http_send_data(pcb, hs);
  } else {
    /* this should normally not happen, print to be robust */
    LWIP_DEBUGF(HTTPD_DEBUG, ("http_sent: no bytes left\n"));
    http_close_conn(pcb, hs);
  }
  return ERR_OK;
}
Ejemplo n.º 3
0
int
http_send_content_length_header(http_t *ctx)
{
  if ((uint64_t) -1 != ctx->content_length) {
    static const char length_hdr[] = "Content-Length: ";
    char buf[UINT64_DEC_BUFLEN];

    http_send_data(ctx, length_hdr, sizeof length_hdr - 1);
    if (ctx->content_length > (uint32_t) -1) {
      print_uint64(buf, sizeof buf, ctx->content_length);
    } else {
      print_uint32(buf, sizeof buf, ctx->content_length);
    }
    return http_send_line(ctx, buf);
  }
  return 0;
}
Ejemplo n.º 4
0
Archivo: http.c Proyecto: gitpan/zxid
/* Called by: */
int http_decode(struct hi_thr* hit, struct hi_io* io)
{
  struct hi_pdu* req = io->cur_pdu;
  char* url;
  char* url_lim = 0;
  char* p = req->m;
  int n = req->ap - p;
  
  if (n < HTTP_MIN_PDU_SIZE) {   /* too little, need more */
    req->need = HTTP_MIN_PDU_SIZE - n;
    return 0;
  }
  
  if (memcmp(p, "GET /", sizeof("GET /")-1)) {
    ERR("Not a GET HTTP PDU. fd(%x). Got(%.*s)", io->fd, HTTP_MIN_PDU_SIZE, req->m);
    return HI_CONN_CLOSE;
  }

  for (p += 5; p < req->ap - (sizeof(" HTTP/1.0")-2); ++p)
    if (!memcmp(p, " HTTP/1.0\n", sizeof(" HTTP/1.0")-1)) {
      /* Found end of URL */
      url = req->m + 4;
      url_lim = p;
      break;
    }
  
  if (!url_lim) {
    req->need = 1;
    return 0;
  }
  /* *** Proper processing of content-length and setting need to length of PDU is still needed. */
  D("need=%d len=%d buf(%.*s)", req->need, (int)(req->ap-req->m), (int)(req->ap-req->m), req->m);

  hi_add_to_reqs(hit, io, req, HTTP_MIN_PDU_SIZE);

  /* 01234567890
   * GET / HTTP/1.0 */
  switch (req->m[6]) {
  case 'a': http_send_data(hit, io, req, url_lim-url, url); break;
  case 'b': http_send_file(hit, io, req, url_lim-url, url); break;  /* *** */
  default:  http_send_err(hit, io, req, 500, "Error"); break;
  }
  return HI_CONN_CLOSE; /* HTTP/1.0 without keep-alive: close connection after every req-resp */
}
Ejemplo n.º 5
0
/**
 * Data has been received on this pcb.
 * For HTTP 1.0, this should normally only happen once (if the request fits in one packet).
 */
static err_t
http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
  err_t parsed = ERR_ABRT;
  struct http_state *hs = arg;
  LWIP_DEBUGF(HTTPD_DEBUG, ("http_recv: pcb=0x%08X pbuf=0x%08X err=%s\n", pcb, p,
    lwip_strerr(err)));

  if (p != NULL) {
    /* Inform TCP that we have taken the data. */
    tcp_recved(pcb, p->tot_len);
  }

  if (hs == NULL) {
    /* be robust */
    LWIP_DEBUGF(HTTPD_DEBUG, ("Error, http_recv: hs is NULL, abort\n"));
    http_close_conn(pcb, hs);
    return ERR_OK;
  }

  if ((err != ERR_OK) || (p == NULL)) {
    /* error or closed by other side */
    if (p != NULL) {
      pbuf_free(p);
    }
    http_close_conn(pcb, hs);
    return ERR_OK;
  }

  if (hs->file == NULL) {
    parsed = http_parse_request(p, hs);
  } else {
    LWIP_DEBUGF(HTTPD_DEBUG, ("http_recv: already sending data\n"));
  }
  pbuf_free(p);
  if (parsed == ERR_OK) {
    LWIP_DEBUGF(HTTPD_DEBUG, ("http_recv: data %p len %ld\n", hs->file, hs->left));
    http_send_data(pcb, hs);
  } else if (parsed == ERR_ABRT) {
    http_close_conn(pcb, hs);
    return ERR_OK;
  }
  return ERR_OK;
}
Ejemplo n.º 6
0
int
http_redirect(http_t *ctx, const char *url, bool permanent)
{
  static const char location[] = "Location: ";
  
  RUNTIME_ASSERT(url && strlen(url) > 0);

  if (permanent)
    http_send_status_line(ctx, 301, "Moved Permanently");
  else
    http_send_status_line(ctx, 307, "Temporary Redirect");
  
  http_send_line(ctx, http_connection_header(ctx));
  http_send_data(ctx, location, sizeof location - 1);
  http_send_line(ctx, url);
  http_send_extra_headers(ctx);
  http_terminate_headers(ctx);

  return 0;
}
Ejemplo n.º 7
0
int
http_send_document(http_t *ctx, const char *data, size_t size)
{
  RUNTIME_ASSERT(ctx != NULL);

  if (!ctx->status_code) {
    ctx->status_code = 200;
    ctx->status_msg = "OK";
  }
  http_send_status_line(ctx, ctx->status_code, ctx->status_msg);
  http_set_content_length(ctx, size);
  http_send_content_length_header(ctx);
  http_send_line(ctx, http_connection_header(ctx));
  http_send_extra_headers(ctx);
  ACCLOG_SET(ctx->acclog, size, size);
  http_terminate_headers(ctx);

  if (size > 0)
    http_send_data(ctx, data, size);
  
  return 0;
}
Ejemplo n.º 8
0
static int handle_connection(HTTPContext *c)
{
    int len, ret;

    switch(c->state) {
    case HTTPSTATE_WAIT_REQUEST:
        /* timeout ? */
        if ((c->timeout - cur_time) < 0)
            return -1;
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            return -1;

        /* no need to read if no events */
        if (!(c->poll_entry->revents & POLLIN))
            return 0;
        /* read the data */
    read_loop:
        len = recv(c->fd, c->buffer_ptr, 1, 0);
        if (len < 0) {
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
                return -1;
        } else if (len == 0) {
            if(!c->keep_alive)return -1;
        } else {
            /* search for end of request. */
            uint8_t *ptr;
            c->buffer_ptr += len;
            ptr = c->buffer_ptr;
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
                /* request found : parse it and reply */
                ret = http_parse_request(c);
                if (ret < 0)
                    return -1;
            } else if (ptr >= c->buffer_end) {
                /* request too long: cannot do anything */
                return -1;
            } else goto read_loop;
        }
        break;

    case HTTPSTATE_SEND_HEADER:
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            return -1;

        /* no need to write if no events */
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
        if (len < 0) {
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
                goto close_conn;
            }
        } else {
            c->buffer_ptr += len;
            c->data_count += len;
            if (c->buffer_ptr >= c->buffer_end) {
                av_freep(&c->pb_buffer);
				if(c->keep_alive){
					memset(c->buffer, 0, c->buffer_size);
					c->buffer_ptr = c->buffer;
				    c->buffer_end = c->buffer + c->buffer_size - 1; 
					c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
				    c->state = HTTPSTATE_WAIT_REQUEST;
					c->hls_idx = -1;
					http_log("%u alive %s\n", ntohs(c->from_addr.sin_port), c->url);
					return 0;
				}
                /* if error, exit */
                if (c->http_error)
                    return -1;
                /* all the buffer was sent : synchronize to the incoming*/
                c->state = HTTPSTATE_SEND_DATA_HEADER;
                c->buffer_ptr = c->buffer_end = c->buffer;
            }
        }
        break;

    case HTTPSTATE_SEND_DATA:
    case HTTPSTATE_SEND_DATA_HEADER:
    case HTTPSTATE_SEND_DATA_TRAILER:
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
			return -1;
        /* no need to read if no events */
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
        if (http_send_data(c) < 0)
			return -1;
        /* close connection if trailer sent */
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
            return -1;
        break;
    case HTTPSTATE_RECEIVE_DATA:
        /* no need to read if no events */
        if (c->poll_entry->revents & (POLLERR | POLLHUP)){
			HLS *s = NULL;
			if(c->hls_idx >= 0){
				s = &s_hls[c->hls_idx];
				s->flag = 2;
			}
				
			wake_others(c, HTTPSTATE_SEND_DATA_TRAILER); 
            return -1;
        }
        if (!(c->poll_entry->revents & POLLIN))
            return 0;
        if (http_receive_data(c) < 0)
            return -1;
        break;
    case HTTPSTATE_WAIT_FEED:
        /* no need to read if no events */
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP)) /*19*/
            {printf("line %d: %x:%d\n", __LINE__, c->poll_entry->revents, get_socket_error(c->fd)); return -1;} 
        /* nothing to do, we'll be waken up by incoming feed packets */
        break;

    default:
        return -1;
    }
    return 0;

close_conn:
    av_freep(&c->pb_buffer);
    return -1;
}