(root)/
glib-2.79.0/
gio/
win32/
gwinhttpfileoutputstream.c
       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.1 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, see <http://www.gnu.org/licenses/>.
      18   *
      19   * Author: Alexander Larsson <alexl@redhat.com>
      20   * Author: Tor Lillqvist <tml@novell.com>
      21   */
      22  
      23  #include "config.h"
      24  
      25  #include <glib.h>
      26  
      27  #include "gio/gcancellable.h"
      28  #include "gio/gioerror.h"
      29  #include "gwinhttpfileoutputstream.h"
      30  #include "glibintl.h"
      31  
      32  struct _GWinHttpFileOutputStream
      33  {
      34    GFileOutputStream parent_instance;
      35  
      36    GWinHttpFile *file;
      37    HINTERNET connection;
      38    goffset offset;
      39  };
      40  
      41  struct _GWinHttpFileOutputStreamClass
      42  {
      43    GFileOutputStreamClass parent_class;
      44  };
      45  
      46  #define g_winhttp_file_output_stream_get_type _g_winhttp_file_output_stream_get_type
      47  G_DEFINE_TYPE (GWinHttpFileOutputStream, g_winhttp_file_output_stream, G_TYPE_FILE_OUTPUT_STREAM)
      48  
      49  static gssize     g_winhttp_file_output_stream_write      (GOutputStream     *stream,
      50                                                             const void        *buffer,
      51                                                             gsize              count,
      52                                                             GCancellable      *cancellable,
      53                                                             GError           **error);
      54  
      55  static void
      56  g_winhttp_file_output_stream_finalize (GObject *object)
      57  {
      58    GWinHttpFileOutputStream *winhttp_stream;
      59  
      60    winhttp_stream = G_WINHTTP_FILE_OUTPUT_STREAM (object);
      61  
      62    if (winhttp_stream->connection != NULL)
      63      G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpCloseHandle (winhttp_stream->connection);
      64  
      65    G_OBJECT_CLASS (g_winhttp_file_output_stream_parent_class)->finalize (object);
      66  }
      67  
      68  static void
      69  g_winhttp_file_output_stream_class_init (GWinHttpFileOutputStreamClass *klass)
      70  {
      71    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
      72    GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
      73  
      74    gobject_class->finalize = g_winhttp_file_output_stream_finalize;
      75  
      76    stream_class->write_fn = g_winhttp_file_output_stream_write;
      77  }
      78  
      79  static void
      80  g_winhttp_file_output_stream_init (GWinHttpFileOutputStream *info)
      81  {
      82  }
      83  
      84  /*
      85   * g_winhttp_file_output_stream_new:
      86   * @file: the GWinHttpFile being read
      87   * @connection: handle to the HTTP connection, as from WinHttpConnect()
      88   * @request: handle to the HTTP request, as from WinHttpOpenRequest
      89   *
      90   * Returns: #GFileOutputStream for the given request
      91   */
      92  GFileOutputStream *
      93  _g_winhttp_file_output_stream_new (GWinHttpFile *file,
      94                                     HINTERNET     connection)
      95  {
      96    GWinHttpFileOutputStream *stream;
      97  
      98    stream = g_object_new (G_TYPE_WINHTTP_FILE_OUTPUT_STREAM, NULL);
      99  
     100    stream->file = file;
     101    stream->connection = connection;
     102    stream->offset = 0;
     103  
     104    return G_FILE_OUTPUT_STREAM (stream);
     105  }
     106  
     107  static gssize
     108  g_winhttp_file_output_stream_write (GOutputStream  *stream,
     109                                      const void     *buffer,
     110                                      gsize           count,
     111                                      GCancellable   *cancellable,
     112                                      GError        **error)
     113  {
     114    GWinHttpFileOutputStream *winhttp_stream = G_WINHTTP_FILE_OUTPUT_STREAM (stream);
     115    HINTERNET request;
     116    char *headers;
     117    wchar_t *wheaders;
     118    DWORD bytes_written;
     119  
     120    request = G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpOpenRequest
     121      (winhttp_stream->connection,
     122       L"PUT",
     123       winhttp_stream->file->url.lpszUrlPath,
     124       NULL,
     125       WINHTTP_NO_REFERER,
     126       NULL,
     127       winhttp_stream->file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0);
     128  
     129    if (request == NULL)
     130      {
     131        _g_winhttp_set_error (error, GetLastError (), "PUT request");
     132  
     133        return -1;
     134      }
     135  
     136    headers = g_strdup_printf ("Content-Range: bytes %" G_GINT64_FORMAT "-%" G_GINT64_FORMAT "/*\r\n",
     137                               winhttp_stream->offset, winhttp_stream->offset + count);
     138    wheaders = g_utf8_to_utf16 (headers, -1, NULL, NULL, NULL);
     139    g_free (headers);
     140  
     141    if (!G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpSendRequest
     142        (request,
     143         wheaders, -1,
     144         NULL, 0,
     145         count,
     146         0))
     147      {
     148        _g_winhttp_set_error (error, GetLastError (), "PUT request");
     149  
     150        G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpCloseHandle (request);
     151        g_free (wheaders);
     152  
     153        return -1;
     154      }
     155  
     156    g_free (wheaders);
     157  
     158    if (!G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpWriteData
     159        (request, buffer, count, &bytes_written))
     160      {
     161        _g_winhttp_set_error (error, GetLastError (), "PUT request");
     162  
     163        G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpCloseHandle (request);
     164  
     165        return -1;
     166      }
     167  
     168    winhttp_stream->offset += bytes_written;
     169  
     170    if (!_g_winhttp_response (winhttp_stream->file->vfs,
     171                              request,
     172                              error,
     173                              "PUT request"))
     174      {
     175        G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpCloseHandle (request);
     176  
     177        return -1;
     178      }
     179  
     180    G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->funcs->pWinHttpCloseHandle (request);
     181  
     182    return bytes_written;
     183  }