📄 http.c
字号:
/*-*-linux-c-*-*//* * gnewtellium - Newtella for Unix * Copyright (C) 2001 Elias Athanasopoulos * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* HTTP header build/parse functions */#include <stdlib.h>#include <string.h>#include <gtk/gtk.h>#include "http.h"#include "memory.h"char *http_header_build(struct http_header *http){ char *http_string = NULL; switch (http->func) { case HTTP_RESPONSE: /* HTTP 200 = OK */ if (http->code == 200) { http_string = newtella_malloc(HTTP_RESPONSE_SIZE); g_snprintf(http_string, HTTP_RESPONSE_SIZE, "HTTP/1.1 200 OK\r\n" "Server: %s\r\n" "Content-type: mp3\r\n" "Content-length: %u\r\n\r\n", http->user_agent, http->content_length); } /* HTTP 404 = Not Found */ if (http->code == 404) { http_string = newtella_malloc(HTTP_RESPONSE_SIZE); g_snprintf(http_string, HTTP_RESPONSE_SIZE, "HTTP/1.1 404 Not Found\r\n" "Server: %s\r\n\r\n", http->user_agent); } /* HTTP 503 = Busy */ if (http->code == 503) { http_string = newtella_malloc(HTTP_RESPONSE_SIZE); g_snprintf(http_string, HTTP_RESPONSE_SIZE, "HTTP/1.1 503 Server is busy\r\n" "Server: %s\r\n\r\n", http->user_agent); } break; case HTTP_GET: http_string = newtella_malloc(HTTP_GET_SIZE + strlen(http->file_name)); g_snprintf(http_string, HTTP_GET_SIZE + strlen(http->file_name), "GET /get/%i/%s HTTP/1.0\r\n" "Connection: Keep-Alive\r\n" "Range: bytes=%u-\r\n" "User-Agent: %s\r\n\r\n", http->file_index, http->file_name, http->range_start, http->user_agent); break; case HTTP_GIV: /* remember that we add 16 bytes for the guid */ http_string = newtella_malloc(HTTP_GIV_SIZE + strlen(http->file_name) + 16); g_snprintf(http_string, HTTP_GIV_SIZE + strlen(http->file_name) + 16, "GIV %d:%s/%s\n\n", http->file_index, http->guid, http->file_name); break; } return http_string; }int http_header_size(char *buf){ /* Returns the size of an HTTP header. A 'valid' header must end in a '\r\n\r\n'. If we don't find the double '\r\n' we return 0. */ char *seek, *tmp = buf; int buf_size = strlen(buf);try_again: seek = memchr(tmp, '\r', buf_size); if (!seek) return 0; if (!memcmp(seek, "\r\n\r\n", 4)) return (seek-buf)+4; else { tmp = seek + 1; goto try_again; }}int http_giv_size(char *buf){ /* Returns the size of a GIV header. A 'valid' header must end in a '\n\n'. If we don't find the double '\n' we return 0. */ char *seek, *tmp = buf; int buf_size = strlen(buf);try_again: seek = memchr(tmp, '\n', buf_size); if (!seek) return 0; if (!memcmp(seek, "\n\n", 2)) return (seek-buf)+2; else { tmp = seek + 1; goto try_again; }}char *http_extract_var(const char *tag, char *buf){ /* This function returns the value of a specific tag (i.e. Server) of an HTTP header response. It's very kludgy but it works. :-) I'll try to add lots of comments because in a week I will be totaly unaware of how it works. Consider: foo: bar\r\n bar = http_extract_var("foo", http_buffer); */ char *v, *n, *seek; char *tmp; int buf_size = http_header_size(buf); int parsed = 0; /* a temp buffer to copy the HTTP header, cause we want to manipulate its contents */ tmp = newtella_malloc(buf_size); memcpy(tmp, buf, buf_size); seek = tmp; try_again: /* find the first '\n'. there is great possibility that the next byte is the start of the wanted tag. if we don't find any '\n's the wanted tag doesn't exist, so we return null */ if (parsed == buf_size) return NULL; n = memchr(seek, '\n', buf_size); if (!n) return NULL; *n = '\0'; n++; parsed = (n - tmp); /* find the first ':' after an '\n' in order to isolate the _tag_ */ v = memchr(n, ':', buf_size-parsed); if (!v) return NULL; *v = '\0'; v++; parsed = (v - tmp); /* is it the tag we wanted? if yes isolate the _value_ otherwise start again from where we stopped infinite loop is not possible because we return null if we don't find either an '\n' or an ':' */ if (!g_strncasecmp(tag, n, strlen(tag))) { seek = memchr(v, '\r', buf_size-parsed); *seek = '\0'; } else goto try_again; /* copy the value in a new buffer, in order to return it, and free the temporary one. The increment is for the space after the ':' */ n = newtella_malloc(strlen(++v)+1); strcpy(n, v); newtella_free(tmp); return n;}struct http_header *http_header_parse(char *http_string){ struct http_header *http = newtella_malloc(sizeof(struct http_header)); gchar *p; /* Try to parse the header. It might *not* be a complete or a valid header. If we return the http structure with valid=1, then this means that we parsed it all correctly. Remember: \r\n\r\n (double) means end of the HTTP message. */ http->valid = 0; if (!memcmp(http_string, "HTTP", 4)) goto parse_response; else if (!memcmp(http_string, "GET ", 4)) goto parse_get; else if (!memcmp(http_string, "GIV ", 4)) goto parse_giv; parse_response: /* get the HTTP code */ http_string = memchr(http_string, ' ', strlen(http_string)); http_string++; http->code = atoi(http_string); switch (http->code) { /* OK */ case 200: /* get the server */ http->user_agent = http_extract_var("Server", http_string); /* get the content type */ http->content_type = http_extract_var("Content-type", http_string); /* get the content length */ http->content_length = atol(http_extract_var("Content-length", http_string)); /* get the content range start -- Content-Range: bytes= */ p = http_extract_var("Content-Range", http_string); if (p) http->range_start = atol(p+6); /* not very safe */ if (http->content_length) http->valid = 1; break; /* RESUME */ case 206: /* get the server */ http->user_agent = http_extract_var("Server", http_string); /* get the content type */ http->content_type = http_extract_var("Content-type", http_string); /* get the content length */ http->content_length = atol(http_extract_var("Content-length" , http_string)); /* get the content range start -- Content-Range: bytes= */ http->range_start = atol(http_extract_var("Content-Range", http_string)+6); /* not very safe */ if (http->content_length) http->valid = 1; break; /* BUSY */ case 404: http->user_agent = http_extract_var("Server", http_string); http->valid = 1; break; case 503: http->user_agent = http_extract_var("Server", http_string); http->valid = 1; break; default: http->valid = 0; break; } return http; parse_get: /* GET /get/file_index/file_name HTTP/1.0\r\n */ http->file_index = atoi(http_string + 9); if (http->file_index) { /* get the file name */ char *seek, *range_str = NULL; int step = 0; seek = strchr(http_string + 9, '/'); if (!seek) return http; seek++; while (*seek++ != ' ') { step++; /* not found */ if (*seek == '\0') return http; } http->file_name = newtella_malloc(step + 1); memcpy(http->file_name, seek-step, step); /* Connection: Keep-Alive */ http->connection = http_extract_var("Connection", seek); /* get range */ range_str = http_extract_var("Range", seek); if (range_str) { /* parse the range string */ seek = strchr(range_str, '='); if (!seek) return http; http->range_start = atol(seek++); seek = strchr(seek, '-'); http->range_end = atol(seek++); http->valid = 1; } return http; } parse_giv: /* TODO */ return http;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -