Home | History | Annotate | Download | only in win32
      1 /* GIO - GLib Input, Output and Streaming Library
      2  *
      3  * Copyright (C) 2006-2007 Red Hat, Inc.
      4  * Copyright (C) 2008 Novell, Inc.
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Lesser General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Lesser General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Lesser General
     17  * Public License along with this library; if not, write to the
     18  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
     19  * Boston, MA 02111-1307, USA.
     20  *
     21  * Author: Alexander Larsson <alexl (at) redhat.com>
     22  * Author: Tor Lillqvist <tml (at) novell.com>
     23  */
     24 
     25 #include "config.h"
     26 
     27 #include <glib.h>
     28 
     29 #include "gcancellable.h"
     30 #include "gioerror.h"
     31 #include "gwinhttpfileoutputstream.h"
     32 #include "glibintl.h"
     33 
     34 #include "gioalias.h"
     35 
     36 struct _GWinHttpFileOutputStream
     37 {
     38   GFileOutputStream parent_instance;
     39 
     40   GWinHttpFile *file;
     41   HINTERNET connection;
     42   goffset offset;
     43 };
     44 
     45 struct _GWinHttpFileOutputStreamClass
     46 {
     47   GFileOutputStreamClass parent_class;
     48 };
     49 
     50 #define g_winhttp_file_output_stream_get_type _g_winhttp_file_output_stream_get_type
     51 G_DEFINE_TYPE (GWinHttpFileOutputStream, g_winhttp_file_output_stream, G_TYPE_FILE_OUTPUT_STREAM);
     52 
     53 static gssize     g_winhttp_file_output_stream_write      (GOutputStream     *stream,
     54                                                            const void        *buffer,
     55                                                            gsize              count,
     56                                                            GCancellable      *cancellable,
     57                                                            GError           **error);
     58 
     59 static void
     60 g_winhttp_file_output_stream_finalize (GObject *object)
     61 {
     62   GWinHttpFileOutputStream *winhttp_stream;
     63 
     64   winhttp_stream = G_WINHTTP_FILE_OUTPUT_STREAM (object);
     65 
     66   if (winhttp_stream->connection != NULL)
     67     G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpCloseHandle (winhttp_stream->connection);
     68 
     69   G_OBJECT_CLASS (g_winhttp_file_output_stream_parent_class)->finalize (object);
     70 }
     71 
     72 static void
     73 g_winhttp_file_output_stream_class_init (GWinHttpFileOutputStreamClass *klass)
     74 {
     75   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     76   GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
     77 
     78   gobject_class->finalize = g_winhttp_file_output_stream_finalize;
     79 
     80   stream_class->write_fn = g_winhttp_file_output_stream_write;
     81 }
     82 
     83 static void
     84 g_winhttp_file_output_stream_init (GWinHttpFileOutputStream *info)
     85 {
     86 }
     87 
     88 /**
     89  * g_winhttp_file_output_stream_new:
     90  * @file: the GWinHttpFile being read
     91  * @connection: handle to the HTTP connection, as from WinHttpConnect()
     92  * @request: handle to the HTTP request, as from WinHttpOpenRequest
     93  *
     94  * Returns: #GFileOutputStream for the given request
     95  **/
     96 GFileOutputStream *
     97 _g_winhttp_file_output_stream_new (GWinHttpFile *file,
     98                                    HINTERNET     connection)
     99 {
    100   GWinHttpFileOutputStream *stream;
    101 
    102   stream = g_object_new (G_TYPE_WINHTTP_FILE_OUTPUT_STREAM, NULL);
    103 
    104   stream->file = file;
    105   stream->connection = connection;
    106   stream->offset = 0;
    107 
    108   return G_FILE_OUTPUT_STREAM (stream);
    109 }
    110 
    111 static gssize
    112 g_winhttp_file_output_stream_write (GOutputStream  *stream,
    113                                     const void     *buffer,
    114                                     gsize           count,
    115                                     GCancellable   *cancellable,
    116                                     GError        **error)
    117 {
    118   GWinHttpFileOutputStream *winhttp_stream = G_WINHTTP_FILE_OUTPUT_STREAM (stream);
    119   HINTERNET request;
    120   char *headers;
    121   wchar_t *wheaders;
    122   DWORD bytes_written;
    123 
    124   request = G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpOpenRequest
    125     (winhttp_stream->connection,
    126      L"PUT",
    127      winhttp_stream->file->url.lpszUrlPath,
    128      NULL,
    129      WINHTTP_NO_REFERER,
    130      NULL,
    131      winhttp_stream->file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0);
    132 
    133   if (request == NULL)
    134     {
    135       _g_winhttp_set_error (error, GetLastError (), "PUT request");
    136 
    137       return -1;
    138     }
    139 
    140   headers = g_strdup_printf ("Content-Range: bytes %" G_GINT64_FORMAT "-%" G_GINT64_FORMAT "/*\r\n",
    141                              winhttp_stream->offset, winhttp_stream->offset + count);
    142   wheaders = g_utf8_to_utf16 (headers, -1, NULL, NULL, NULL);
    143   g_free (headers);
    144 
    145   if (!G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpSendRequest
    146       (request,
    147        wheaders, -1,
    148        NULL, 0,
    149        count,
    150        0))
    151     {
    152       _g_winhttp_set_error (error, GetLastError (), "PUT request");
    153 
    154       G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpCloseHandle (request);
    155       g_free (wheaders);
    156 
    157       return -1;
    158     }
    159 
    160   g_free (wheaders);
    161 
    162   if (!G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpWriteData
    163       (request, buffer, count, &bytes_written))
    164     {
    165       _g_winhttp_set_error (error, GetLastError (), "PUT request");
    166 
    167       G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpCloseHandle (request);
    168 
    169       return -1;
    170     }
    171 
    172   winhttp_stream->offset += bytes_written;
    173 
    174   if (!_g_winhttp_response (winhttp_stream->file->vfs,
    175                             request,
    176                             error,
    177                             "PUT request"))
    178     {
    179       G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpCloseHandle (request);
    180 
    181       return -1;
    182     }
    183 
    184   G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpCloseHandle (request);
    185 
    186   return bytes_written;
    187 }
    188