[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [libmicrohttpd] seeking file server
From: |
Christian Grothoff |
Subject: |
Re: [libmicrohttpd] seeking file server |
Date: |
Mon, 2 Aug 2010 21:48:15 +0200 |
User-agent: |
KMail/1.13.2 (Linux/2.6.32-24-generic; KDE/4.4.2; i686; ; ) |
Hi Ronny,
I'm pretty sure your problems are not with MHD but with the HTTP
specification. My reading is that you should not use "HTTP 200 OK" but "HTTP
206 Partial Content" for the reply. Also, your content range header seems to
be malformed. If I read section 14.16 of RFC 2616 (see
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) correctly, you must
not just give the starting offset but also the end AND the total length of the
file, so something like:
Content-Range: bytes 123455-53525/526234
Btw, having a working example for range queries would likely be nice for
others, so if you would share your code so that we can put it into the
repository once it working, I'd appreciate it.
Also, if this doesn't work, please ask again with the updated code. I'll be
happy to take a second look.
Best,
Christian
On Monday, August 02, 2010 05:40:38 am Ronny Falk wrote:
> Hi,
> I am trying to implement a seeking file server with MHD. My prototype looks
> almost like the fileserver example (see below).
>
> A few questions regarding this:
> I am playing a file via mplayer http://localhost:8001/anything
> mplayers HTTP GET commands look like this:
> GET /s.avi HTTP/1.0
> Host: macbook.local
> User-Agent: MPlayer VERSION
> Icy-MetaData: 1
> Connection: close
>
> GET /s.avi HTTP/1.0
> Host: macbook.local
> User-Agent: MPlayer VERSION
> Icy-MetaData: 1
> Range: bytes=14159872-
> Connection: close
>
> GET /s.avi HTTP/1.0
> Host: macbook.local
> User-Agent: MPlayer VERSION
> Icy-MetaData: 1
> Range: bytes=10240-
> Connection: close
>
> GET /s.avi HTTP/1.0
> Host: macbook.local
> User-Agent: MPlayer VERSION
> Icy-MetaData: 1
> Range: bytes=13590528-
> Connection: close
>
> So I thought, I need to reply to the range: bytes=n header.
>
> Is there a good way of doing this, rather than this:
>
> {
> char br[64];
> sprintf(br, "bytes %lu-", byteRange);
>
> fseek(file, byteRange, SEEK_SET);
> response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
>
> 32 * 1024, /* 32k
page size */
>
> &file_reader,
>
> file,
>
> &free_callback);
>
> MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE,
> "video/x-msvideo"); //MHD_add_response_header(response,
> MHD_HTTP_HEADER_ETAG, "519240-d8e800-489aa5cc98940");
> MHD_add_response_header(response, MHD_HTTP_HEADER_ACCEPT_RANGES, "bytes");
> //MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_LENGTH,
> "14215168"); MHD_add_response_header(response,
> MHD_HTTP_HEADER_CONTENT_RANGE, br); ...
> }
>
> I do not get the video to play, I get those connection headers though:
> Connection:close
> Icy-MetaData:1
> User-Agent:MPlayer/SVN-r31524-4.0.1
> Host:localhost:8001
> result h:4, byteRange:0
>
> Connection:close
> Icy-MetaData:1
> User-Agent:MPlayer/SVN-r31524-4.0.1
> Host:localhost:8001
> result h:4, byteRange:0
>
> Connection:close
> Range:bytes=14159872-
> Icy-MetaData:1
> User-Agent:MPlayer/SVN-r31524-4.0.1
> Host:localhost:8001
> result h:5, byteRange:14159872
>
> Connection:close
> Range:bytes=14159872-
> Icy-MetaData:1
> User-Agent:MPlayer/SVN-r31524-4.0.1
> Host:localhost:8001
> result h:5, byteRange:14159872
>
> Please help, I am stuck on this one for a couple of days now.
>
> cheers
> Ronny
>
> /*
> This file is part of libmicrohttpd
> (C) 2007 Christian Grothoff (and other contributing authors)
>
> This library is free software; you can redistribute it and/or
> modify it under the terms of the GNU Lesser General Public
> License as published by the Free Software Foundation; either
> version 2.1 of the License, or (at your option) any later version.
>
> This library 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
> Lesser General Public License for more details.
>
> You should have received a copy of the GNU Lesser General Public
> License along with this library; if not, write to the Free Software
> Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
> USA */
>
> /**
> * @file fileserver_example.c
> * @brief minimal example for how to use libmicrohttpd to serve files
> * @author Christian Grothoff
> */
>
>
> #include <fcntl.h>
> #include <stdio.h>
> #include <stdint.h>
> #include <sys/types.h>
> #include <sys/select.h>
> #include <sys/socket.h>
> #include <sys/stat.h>
> #include <stdlib.h>
> #include <string.h>
> #include <stdio.h>
> #include <microhttpd.h>
> #include <unistd.h>
>
> #define PAGE "<html><head><title>File not found</title></head><body>File
> not found</body></html>"
>
> static int
> file_reader (void *cls, uint64_t pos, char *buf, int max)
> {
> FILE *file = cls;
>
> //(void) fseek (file, pos, SEEK_SET);
> return fread (buf, 1, max, file);
> }
>
> static void
> free_callback (void *cls)
> {
> FILE *file = cls;
> fclose (file);
> }
>
> static int
> header_iterator (void *cls,
> enum MHD_ValueKind kind,
> const char *key,
> const char *value) {
>
> printf("%s:%s\n", key, value);
> if (!strcmp(key, MHD_HTTP_HEADER_RANGE)) {
> //parse Range
> //HACKHACK: assume "bytes=%i-"
> *(long*)cls = atoi(value + 6);
> }
> return MHD_YES;
> }
>
> static int
> ahc_echo (void *cls,
> struct MHD_Connection *connection,
> const char *url,
> const char *method,
> const char *version,
> const char *upload_data,
> size_t *upload_data_size, void **ptr)
> {
> static int aptr;
> struct MHD_Response *response;
> int ret;
> FILE *file;
> char *fileURL = "/tmp/s.avi";
> struct stat buf;
> long byteRange;
>
> if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
> return MHD_NO; /* unexpected method */
>
> int h = MHD_get_connection_values(connection,
>
> MHD_HEADER_KIND,
>
> &header_iterator,
>
> &byteRange);
> // printf("result h:%i\n", h);
>
> if (&aptr != *ptr)
> {
> /* do never respond on first call */
> *ptr = &aptr;
> return MHD_YES;
> }
> *ptr = NULL; /* reset when done */
> if (0 == stat (fileURL, &buf))
> file = fopen (fileURL, "rb");
> else
> file = NULL;
> if (file == NULL)
> {
> response = MHD_create_response_from_data (strlen (PAGE),
>
> (void *) PAGE,
>
> MHD_NO, MHD_NO);
> ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND,
> response);
> MHD_destroy_response (response);
> }
> else
> {
> char br[64];
> sprintf(br, "bytes %lu-", byteRange);
>
> fseek(file, byteRange, SEEK_SET);
> response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
>
> 32 * 1024, /* 32k
page size */
>
> &file_reader,
>
> file,
>
> &free_callback);
>
> MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE,
> "video/x-msvideo"); //MHD_add_response_header(response,
> MHD_HTTP_HEADER_ETAG, "519240-d8e800-489aa5cc98940");
> MHD_add_response_header(response, MHD_HTTP_HEADER_ACCEPT_RANGES, "bytes");
> //MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_LENGTH,
> "14215168"); MHD_add_response_header(response,
> MHD_HTTP_HEADER_CONTENT_RANGE, br);
>
> if (response == NULL)
> {
> fclose (file);
> return MHD_NO;
> }
> ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
>
> MHD_destroy_response (response);
> }
> return ret;
> }
>
> int
> main (int argc, char *const *argv)
> {
> struct MHD_Daemon *d;
>
> // if (argc != 2)
> // {
> // printf ("%s PORT\n", argv[0]);
> // return 1;
> // }
> d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
> 8001,
> NULL, NULL, &ahc_echo, PAGE,
> MHD_OPTION_END);
> if (d == NULL)
> return 1;
> (void) getc (stdin);
> MHD_stop_daemon (d);
> return 0;
> }