libmicrohttpd
[Top][All Lists]
Advanced

[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;
> }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]