Blame gio/win32/gwinhttpfile.c

Packit ae235b
/* GIO - GLib Input, Output and Streaming Library
Packit ae235b
 *
Packit ae235b
 * Copyright (C) 2006-2007 Red Hat, Inc.
Packit ae235b
 * Copyright (C) 2008 Novell, Inc.
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General
Packit ae235b
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 *
Packit ae235b
 * Author: Alexander Larsson <alexl@redhat.com>
Packit ae235b
 * Author: Tor Lillqvist <tml@novell.com>
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
Packit ae235b
#include <stdio.h>
Packit ae235b
#include <string.h>
Packit ae235b
#include <wchar.h>
Packit ae235b
Packit ae235b
#include "gio/gfile.h"
Packit ae235b
#include "gio/gfileattribute.h"
Packit ae235b
#include "gio/gfileinfo.h"
Packit ae235b
#include "gwinhttpfile.h"
Packit ae235b
#include "gwinhttpfileinputstream.h"
Packit ae235b
#include "gwinhttpfileoutputstream.h"
Packit ae235b
#include "gio/gioerror.h"
Packit ae235b
Packit ae235b
#include "glibintl.h"
Packit ae235b
Packit ae235b
static void g_winhttp_file_file_iface_init (GFileIface *iface);
Packit ae235b
Packit ae235b
#define g_winhttp_file_get_type _g_winhttp_file_get_type
Packit ae235b
G_DEFINE_TYPE_WITH_CODE (GWinHttpFile, g_winhttp_file, G_TYPE_OBJECT,
Packit ae235b
                         G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
Packit ae235b
                                                g_winhttp_file_file_iface_init))
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_winhttp_file_finalize (GObject *object)
Packit ae235b
{
Packit ae235b
  GWinHttpFile *file;
Packit ae235b
Packit ae235b
  file = G_WINHTTP_FILE (object);
Packit ae235b
Packit ae235b
  g_free (file->url.lpszScheme);
Packit ae235b
  g_free (file->url.lpszHostName);
Packit ae235b
  g_free (file->url.lpszUserName);
Packit ae235b
  g_free (file->url.lpszPassword);
Packit ae235b
  g_free (file->url.lpszUrlPath);
Packit ae235b
  g_free (file->url.lpszExtraInfo);
Packit ae235b
Packit ae235b
  g_object_unref (file->vfs);
Packit ae235b
Packit ae235b
  G_OBJECT_CLASS (g_winhttp_file_parent_class)->finalize (object);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_winhttp_file_class_init (GWinHttpFileClass *klass)
Packit ae235b
{
Packit ae235b
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit ae235b
Packit ae235b
  gobject_class->finalize = g_winhttp_file_finalize;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_winhttp_file_init (GWinHttpFile *winhttp)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
/*
Packit ae235b
 * _g_winhttp_file_new:
Packit ae235b
 * @vfs: GWinHttpVfs to use
Packit ae235b
 * @uri: URI of the GWinHttpFile to create.
Packit ae235b
 *
Packit ae235b
 * Returns: new winhttp #GFile.
Packit ae235b
 */
Packit ae235b
GFile *
Packit ae235b
_g_winhttp_file_new (GWinHttpVfs *vfs,
Packit ae235b
                     const char  *uri)
Packit ae235b
{
Packit ae235b
  wchar_t *wuri;
Packit ae235b
  GWinHttpFile *file;
Packit ae235b
Packit ae235b
  wuri = g_utf8_to_utf16 (uri, -1, NULL, NULL, NULL);
Packit ae235b
Packit ae235b
  if (wuri == NULL)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  file = g_object_new (G_TYPE_WINHTTP_FILE, NULL);
Packit ae235b
  file->vfs = g_object_ref (vfs);
Packit ae235b
Packit ae235b
  memset (&file->url, 0, sizeof (file->url));
Packit ae235b
  file->url.dwStructSize = sizeof (file->url);
Packit ae235b
  file->url.dwSchemeLength = 1;
Packit ae235b
  file->url.dwHostNameLength = 1;
Packit ae235b
  file->url.dwUserNameLength = 1;
Packit ae235b
  file->url.dwPasswordLength = 1;
Packit ae235b
  file->url.dwUrlPathLength = 1;
Packit ae235b
  file->url.dwExtraInfoLength = 1;
Packit ae235b
Packit ae235b
  if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpCrackUrl (wuri, 0, 0, &file->url))
Packit ae235b
    {
Packit ae235b
      g_free (wuri);
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  file->url.lpszScheme = g_new (wchar_t, ++file->url.dwSchemeLength);
Packit ae235b
  file->url.lpszHostName = g_new (wchar_t, ++file->url.dwHostNameLength);
Packit ae235b
  file->url.lpszUserName = g_new (wchar_t, ++file->url.dwUserNameLength);
Packit ae235b
  file->url.lpszPassword = g_new (wchar_t, ++file->url.dwPasswordLength);
Packit ae235b
  file->url.lpszUrlPath = g_new (wchar_t, ++file->url.dwUrlPathLength);
Packit ae235b
  file->url.lpszExtraInfo = g_new (wchar_t, ++file->url.dwExtraInfoLength);
Packit ae235b
Packit ae235b
  if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpCrackUrl (wuri, 0, 0, &file->url))
Packit ae235b
    {
Packit ae235b
      g_free (file->url.lpszScheme);
Packit ae235b
      g_free (file->url.lpszHostName);
Packit ae235b
      g_free (file->url.lpszUserName);
Packit ae235b
      g_free (file->url.lpszPassword);
Packit ae235b
      g_free (file->url.lpszUrlPath);
Packit ae235b
      g_free (file->url.lpszExtraInfo);
Packit ae235b
      g_free (wuri);
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_free (wuri);
Packit ae235b
  return G_FILE (file);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_winhttp_file_is_native (GFile *file)
Packit ae235b
{
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_winhttp_file_has_uri_scheme (GFile      *file,
Packit ae235b
                               const char *uri_scheme)
Packit ae235b
{
Packit ae235b
  return (g_ascii_strcasecmp (uri_scheme, "http") == 0 ||
Packit ae235b
          g_ascii_strcasecmp (uri_scheme, "https") == 0);
Packit ae235b
}
Packit ae235b
Packit ae235b
static char *
Packit ae235b
g_winhttp_file_get_uri_scheme (GFile *file)
Packit ae235b
{
Packit ae235b
  GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
Packit ae235b
Packit ae235b
  return g_utf16_to_utf8 (winhttp_file->url.lpszScheme, -1, NULL, NULL, NULL);
Packit ae235b
}
Packit ae235b
Packit ae235b
static char *
Packit ae235b
g_winhttp_file_get_basename (GFile *file)
Packit ae235b
{
Packit ae235b
  GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
Packit ae235b
  char *basename;
Packit ae235b
  char *last_slash;
Packit ae235b
  char *retval;
Packit ae235b
Packit ae235b
  basename = g_utf16_to_utf8 (winhttp_file->url.lpszUrlPath, -1, NULL, NULL, NULL);
Packit ae235b
  last_slash = strrchr (basename, '/');
Packit ae235b
  /* If no slash, or only "/" fallback to full path part of URI */
Packit ae235b
  if (last_slash == NULL || last_slash[1] == '\0')
Packit ae235b
    return basename;
Packit ae235b
Packit ae235b
  retval = g_strdup (last_slash + 1);
Packit ae235b
  g_free (basename);
Packit ae235b
Packit ae235b
  return retval;
Packit ae235b
}
Packit ae235b
Packit ae235b
static char *
Packit ae235b
g_winhttp_file_get_path (GFile *file)
Packit ae235b
{
Packit ae235b
  return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
static char *
Packit ae235b
g_winhttp_file_get_uri (GFile *file)
Packit ae235b
{
Packit ae235b
  GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
Packit ae235b
  DWORD len;
Packit ae235b
  wchar_t *wuri;
Packit ae235b
  char *retval;
Packit ae235b
Packit ae235b
  len = 0;
Packit ae235b
  if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpCreateUrl (&winhttp_file->url, ICU_ESCAPE, NULL, &len) &&
Packit ae235b
      GetLastError () != ERROR_INSUFFICIENT_BUFFER)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  wuri = g_new (wchar_t, ++len);
Packit ae235b
Packit ae235b
  if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpCreateUrl (&winhttp_file->url, ICU_ESCAPE, wuri, &len))
Packit ae235b
    {
Packit ae235b
      g_free (wuri);
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  retval = g_utf16_to_utf8 (wuri, -1, NULL, NULL, NULL);
Packit ae235b
  g_free (wuri);
Packit ae235b
Packit ae235b
  if (g_str_has_prefix (retval, "http://:@"))
Packit ae235b
    {
Packit ae235b
      memmove (retval + 7, retval + 9, strlen (retval) - 9);
Packit ae235b
      retval[strlen (retval) - 2] = '\0';
Packit ae235b
    }
Packit ae235b
  else if (g_str_has_prefix (retval, "https://:@"))
Packit ae235b
    {
Packit ae235b
      memmove (retval + 8, retval + 10, strlen (retval) - 10);
Packit ae235b
      retval[strlen (retval) - 2] = '\0';
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return retval;
Packit ae235b
}
Packit ae235b
Packit ae235b
static char *
Packit ae235b
g_winhttp_file_get_parse_name (GFile *file)
Packit ae235b
{
Packit ae235b
  /* FIXME: More hair surely needed */
Packit ae235b
Packit ae235b
  return g_winhttp_file_get_uri (file);
Packit ae235b
}
Packit ae235b
Packit ae235b
static GFile *
Packit ae235b
g_winhttp_file_get_parent (GFile *file)
Packit ae235b
{
Packit ae235b
  GWinHttpFile *winhttp_file;
Packit ae235b
  char *uri;
Packit ae235b
  char *last_slash;
Packit ae235b
  GFile *parent;
Packit ae235b
Packit ae235b
  winhttp_file = G_WINHTTP_FILE (file);
Packit ae235b
Packit ae235b
  uri = g_winhttp_file_get_uri (file);
Packit ae235b
  if (uri == NULL)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  last_slash = strrchr (uri, '/');
Packit ae235b
  if (last_slash == NULL || *(last_slash+1) == 0)
Packit ae235b
    {
Packit ae235b
      g_free (uri);
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  while (last_slash > uri && *last_slash == '/')
Packit ae235b
    last_slash--;
Packit ae235b
Packit ae235b
  last_slash[1] = '\0';
Packit ae235b
Packit ae235b
  parent = _g_winhttp_file_new (winhttp_file->vfs, uri);
Packit ae235b
  g_free (uri);
Packit ae235b
Packit ae235b
  return parent;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GFile *
Packit ae235b
g_winhttp_file_dup (GFile *file)
Packit ae235b
{
Packit ae235b
  GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
Packit ae235b
  char *uri = g_winhttp_file_get_uri (file);
Packit ae235b
  GFile *retval = _g_winhttp_file_new (winhttp_file->vfs, uri);
Packit ae235b
Packit ae235b
  g_free (uri);
Packit ae235b
Packit ae235b
  return retval;
Packit ae235b
}
Packit ae235b
Packit ae235b
static guint
Packit ae235b
g_winhttp_file_hash (GFile *file)
Packit ae235b
{
Packit ae235b
  char *uri = g_winhttp_file_get_uri (file);
Packit ae235b
  guint retval = g_str_hash (uri);
Packit ae235b
Packit ae235b
  g_free (uri);
Packit ae235b
Packit ae235b
  return retval;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_winhttp_file_equal (GFile *file1,
Packit ae235b
                      GFile *file2)
Packit ae235b
{
Packit ae235b
  char *uri1 = g_winhttp_file_get_uri (file1);
Packit ae235b
  char *uri2 = g_winhttp_file_get_uri (file2);
Packit ae235b
  gboolean retval = g_str_equal (uri1, uri2);
Packit ae235b
Packit ae235b
  g_free (uri1);
Packit ae235b
  g_free (uri2);
Packit ae235b
Packit ae235b
  return retval;
Packit ae235b
}
Packit ae235b
Packit ae235b
static const char *
Packit ae235b
match_prefix (const char *path,
Packit ae235b
              const char *prefix)
Packit ae235b
{
Packit ae235b
  int prefix_len;
Packit ae235b
Packit ae235b
  prefix_len = strlen (prefix);
Packit ae235b
  if (strncmp (path, prefix, prefix_len) != 0)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  if (prefix_len > 0 && prefix[prefix_len-1] == '/')
Packit ae235b
    prefix_len--;
Packit ae235b
Packit ae235b
  return path + prefix_len;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_winhttp_file_prefix_matches (GFile *parent,
Packit ae235b
                               GFile *descendant)
Packit ae235b
{
Packit ae235b
  char *parent_uri = g_winhttp_file_get_uri (parent);
Packit ae235b
  char *descendant_uri = g_winhttp_file_get_uri (descendant);
Packit ae235b
  const char *remainder;
Packit ae235b
  gboolean retval;
Packit ae235b
Packit ae235b
  remainder = match_prefix (descendant_uri, parent_uri);
Packit ae235b
Packit ae235b
  if (remainder != NULL && *remainder == '/')
Packit ae235b
    retval = TRUE;
Packit ae235b
  else
Packit ae235b
    retval = FALSE;
Packit ae235b
Packit ae235b
  g_free (parent_uri);
Packit ae235b
  g_free (descendant_uri);
Packit ae235b
Packit ae235b
  return retval;
Packit ae235b
}
Packit ae235b
Packit ae235b
static char *
Packit ae235b
g_winhttp_file_get_relative_path (GFile *parent,
Packit ae235b
                                  GFile *descendant)
Packit ae235b
{
Packit ae235b
  char *parent_uri = g_winhttp_file_get_uri (parent);
Packit ae235b
  char *descendant_uri = g_winhttp_file_get_uri (descendant);
Packit ae235b
  const char *remainder;
Packit ae235b
  char *retval;
Packit ae235b
Packit ae235b
  remainder = match_prefix (descendant_uri, parent_uri);
Packit ae235b
Packit ae235b
  if (remainder != NULL && *remainder == '/')
Packit ae235b
    retval = g_strdup (remainder + 1);
Packit ae235b
  else
Packit ae235b
    retval = NULL;
Packit ae235b
Packit ae235b
  g_free (parent_uri);
Packit ae235b
  g_free (descendant_uri);
Packit ae235b
Packit ae235b
  return retval;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GFile *
Packit ae235b
g_winhttp_file_resolve_relative_path (GFile      *file,
Packit ae235b
                                      const char *relative_path)
Packit ae235b
{
Packit ae235b
  GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
Packit ae235b
  GWinHttpFile *child;
Packit ae235b
  wchar_t *wnew_path = g_utf8_to_utf16 (relative_path, -1, NULL, NULL, NULL);
Packit ae235b
Packit ae235b
  if (wnew_path == NULL)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  if (*wnew_path != '/')
Packit ae235b
    {
Packit ae235b
      wchar_t *tmp = NULL;
Packit ae235b
      int trailing_slash = winhttp_file->url.lpszUrlPath[winhttp_file->url.dwUrlPathLength-1] == L'/'? 1 : 0;
Packit ae235b
      if (trailing_slash)
Packit ae235b
	{
Packit ae235b
	  tmp = g_new (wchar_t, wcslen (winhttp_file->url.lpszUrlPath) + wcslen (wnew_path) + 1);
Packit ae235b
	  wcscpy (tmp, winhttp_file->url.lpszUrlPath);
Packit ae235b
	}
Packit ae235b
      else
Packit ae235b
	{
Packit ae235b
	  tmp = g_new (wchar_t, wcslen (winhttp_file->url.lpszUrlPath) + 1 + wcslen (wnew_path) + 1);
Packit ae235b
	  wcscpy (tmp, winhttp_file->url.lpszUrlPath);
Packit ae235b
	  wcscat (tmp, L"/");
Packit ae235b
	}
Packit ae235b
      wcscat (tmp, wnew_path);
Packit ae235b
Packit ae235b
      g_free (wnew_path);
Packit ae235b
      wnew_path = tmp;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  child = g_object_new (G_TYPE_WINHTTP_FILE, NULL);
Packit ae235b
  child->vfs = winhttp_file->vfs;
Packit ae235b
  child->url = winhttp_file->url;
Packit ae235b
  child->url.lpszScheme = g_memdup (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2);
Packit ae235b
  child->url.lpszHostName = g_memdup (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2);
Packit ae235b
  child->url.lpszUserName = g_memdup (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2);
Packit ae235b
  child->url.lpszPassword = g_memdup (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2);
Packit ae235b
  child->url.lpszUrlPath = wnew_path;
Packit ae235b
  child->url.dwUrlPathLength = wcslen (wnew_path);
Packit ae235b
  child->url.lpszExtraInfo = NULL;
Packit ae235b
  child->url.dwExtraInfoLength = 0;
Packit ae235b
Packit ae235b
  return (GFile *) child;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GFile *
Packit ae235b
g_winhttp_file_get_child_for_display_name (GFile        *file,
Packit ae235b
                                           const char   *display_name,
Packit ae235b
                                           GError      **error)
Packit ae235b
{
Packit ae235b
  GFile *new_file;
Packit ae235b
  char *basename;
Packit ae235b
Packit ae235b
  basename = g_locale_from_utf8 (display_name, -1, NULL, NULL, NULL);
Packit ae235b
  if (basename == NULL)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME,
Packit ae235b
                   _("Invalid filename %s"), display_name);
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  new_file = g_file_get_child (file, basename);
Packit ae235b
  g_free (basename);
Packit ae235b
Packit ae235b
  return new_file;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GFile *
Packit ae235b
g_winhttp_file_set_display_name (GFile         *file,
Packit ae235b
                                 const char    *display_name,
Packit ae235b
                                 GCancellable  *cancellable,
Packit ae235b
                                 GError       **error)
Packit ae235b
{
Packit ae235b
  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
Packit ae235b
                       _("Operation not supported"));
Packit ae235b
Packit ae235b
  return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
static time_t
Packit ae235b
mktime_utc (SYSTEMTIME *t)
Packit ae235b
{
Packit ae235b
  time_t retval;
Packit ae235b
Packit ae235b
  static const gint days_before[] =
Packit ae235b
  {
Packit ae235b
    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
Packit ae235b
  };
Packit ae235b
Packit ae235b
  if (t->wMonth < 1 || t->wMonth > 12)
Packit ae235b
    return (time_t) -1;
Packit ae235b
Packit ae235b
  retval = (t->wYear - 1970) * 365;
Packit ae235b
  retval += (t->wYear - 1968) / 4;
Packit ae235b
  retval += days_before[t->wMonth-1] + t->wDay - 1;
Packit ae235b
Packit ae235b
  if (t->wYear % 4 == 0 && t->wMonth < 3)
Packit ae235b
    retval -= 1;
Packit ae235b
Packit ae235b
  retval = ((((retval * 24) + t->wHour) * 60) + t->wMinute) * 60 + t->wSecond;
Packit ae235b
Packit ae235b
  return retval;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GFileInfo *
Packit ae235b
g_winhttp_file_query_info (GFile                *file,
Packit ae235b
                           const char           *attributes,
Packit ae235b
                           GFileQueryInfoFlags   flags,
Packit ae235b
                           GCancellable         *cancellable,
Packit ae235b
                           GError              **error)
Packit ae235b
{
Packit ae235b
  GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
Packit ae235b
  HINTERNET connection, request;
Packit ae235b
  const wchar_t *accept_types[] =
Packit ae235b
    {
Packit ae235b
      L"*/*",
Packit ae235b
      NULL,
Packit ae235b
    };
Packit ae235b
  GFileInfo *info;
Packit ae235b
  GFileAttributeMatcher *matcher;
Packit ae235b
  char *basename;
Packit ae235b
  wchar_t *content_length;
Packit ae235b
  wchar_t *content_type;
Packit ae235b
  SYSTEMTIME last_modified;
Packit ae235b
  DWORD last_modified_len;
Packit ae235b
Packit ae235b
  connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpConnect
Packit ae235b
    (G_WINHTTP_VFS (winhttp_file->vfs)->session,
Packit ae235b
     winhttp_file->url.lpszHostName,
Packit ae235b
     winhttp_file->url.nPort,
Packit ae235b
     0);
Packit ae235b
Packit ae235b
  if (connection == NULL)
Packit ae235b
    {
Packit ae235b
      _g_winhttp_set_error (error, GetLastError (), "HTTP connection");
Packit ae235b
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  request = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpOpenRequest
Packit ae235b
    (connection,
Packit ae235b
     L"HEAD",
Packit ae235b
     winhttp_file->url.lpszUrlPath,
Packit ae235b
     NULL,
Packit ae235b
     WINHTTP_NO_REFERER,
Packit ae235b
     accept_types,
Packit ae235b
     winhttp_file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0);
Packit ae235b
Packit ae235b
  if (request == NULL)
Packit ae235b
    {
Packit ae235b
      _g_winhttp_set_error (error, GetLastError (), "HEAD request");
Packit ae235b
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpSendRequest
Packit ae235b
      (request,
Packit ae235b
       NULL, 0,
Packit ae235b
       NULL, 0,
Packit ae235b
       0,
Packit ae235b
       0))
Packit ae235b
    {
Packit ae235b
      _g_winhttp_set_error (error, GetLastError (), "HEAD request");
Packit ae235b
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!_g_winhttp_response (winhttp_file->vfs, request, error, "HEAD request"))
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  matcher = g_file_attribute_matcher_new (attributes);
Packit ae235b
  info = g_file_info_new ();
Packit ae235b
  g_file_info_set_attribute_mask (info, matcher);
Packit ae235b
Packit ae235b
  basename = g_winhttp_file_get_basename (file);
Packit ae235b
  g_file_info_set_name (info, basename);
Packit ae235b
  g_free (basename);
Packit ae235b
Packit ae235b
  content_length = NULL;
Packit ae235b
  if (_g_winhttp_query_header (winhttp_file->vfs,
Packit ae235b
                               request,
Packit ae235b
                               "HEAD request",
Packit ae235b
                               WINHTTP_QUERY_CONTENT_LENGTH,
Packit ae235b
                               &content_length,
Packit ae235b
                               NULL))
Packit ae235b
    {
Packit ae235b
      gint64 cl;
Packit ae235b
      int n;
Packit ae235b
      const char *gint64_format = "%"G_GINT64_FORMAT"%n";
Packit ae235b
      wchar_t *gint64_format_w = g_utf8_to_utf16 (gint64_format, -1, NULL, NULL, NULL);
Packit ae235b
Packit ae235b
      if (swscanf (content_length, gint64_format_w, &cl, &n) == 1 &&
Packit ae235b
          n == wcslen (content_length))
Packit ae235b
        g_file_info_set_size (info, cl);
Packit ae235b
Packit ae235b
      g_free (content_length);
Packit ae235b
      g_free (gint64_format_w);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (matcher == NULL)
Packit ae235b
    return info;
Packit ae235b
Packit ae235b
  content_type = NULL;
Packit ae235b
  if (_g_winhttp_query_header (winhttp_file->vfs,
Packit ae235b
                               request,
Packit ae235b
                               "HEAD request",
Packit ae235b
                               WINHTTP_QUERY_CONTENT_TYPE,
Packit ae235b
                               &content_type,
Packit ae235b
                               NULL))
Packit ae235b
    {
Packit ae235b
      char *ct = g_utf16_to_utf8 (content_type, -1, NULL, NULL, NULL);
Packit ae235b
Packit ae235b
      if (ct != NULL)
Packit ae235b
        {
Packit ae235b
          char *p = strchr (ct, ';');
Packit ae235b
Packit ae235b
          if (p != NULL)
Packit ae235b
            {
Packit ae235b
              char *tmp = g_strndup (ct, p - ct);
Packit ae235b
Packit ae235b
              g_file_info_set_content_type (info, tmp);
Packit ae235b
              g_free (tmp);
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            g_file_info_set_content_type (info, ct);
Packit ae235b
        }
Packit ae235b
Packit ae235b
      g_free (ct);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  last_modified_len = sizeof (last_modified);
Packit ae235b
  if (G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpQueryHeaders
Packit ae235b
      (request,
Packit ae235b
       WINHTTP_QUERY_LAST_MODIFIED | WINHTTP_QUERY_FLAG_SYSTEMTIME,
Packit ae235b
       NULL,
Packit ae235b
       &last_modified,
Packit ae235b
       &last_modified_len,
Packit ae235b
       NULL) &&
Packit ae235b
      last_modified_len == sizeof (last_modified) &&
Packit ae235b
      /* Don't bother comparing to the exact Y2038 moment */
Packit ae235b
      last_modified.wYear >= 1970 &&
Packit ae235b
      last_modified.wYear < 2038)
Packit ae235b
    {
Packit ae235b
      GTimeVal tv;
Packit ae235b
Packit ae235b
      tv.tv_sec = mktime_utc (&last_modified);
Packit ae235b
      tv.tv_usec = last_modified.wMilliseconds * 1000;
Packit ae235b
Packit ae235b
      g_file_info_set_modification_time (info, &tv;;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_file_attribute_matcher_unref (matcher);
Packit ae235b
Packit ae235b
  return info;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GFileInputStream *
Packit ae235b
g_winhttp_file_read (GFile         *file,
Packit ae235b
                     GCancellable  *cancellable,
Packit ae235b
                     GError       **error)
Packit ae235b
{
Packit ae235b
  GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
Packit ae235b
  HINTERNET connection, request;
Packit ae235b
  const wchar_t *accept_types[] =
Packit ae235b
    {
Packit ae235b
      L"*/*",
Packit ae235b
      NULL,
Packit ae235b
    };
Packit ae235b
Packit ae235b
  connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpConnect
Packit ae235b
    (G_WINHTTP_VFS (winhttp_file->vfs)->session,
Packit ae235b
     winhttp_file->url.lpszHostName,
Packit ae235b
     winhttp_file->url.nPort,
Packit ae235b
     0);
Packit ae235b
Packit ae235b
  if (connection == NULL)
Packit ae235b
    {
Packit ae235b
      _g_winhttp_set_error (error, GetLastError (), "HTTP connection");
Packit ae235b
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  request = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpOpenRequest
Packit ae235b
    (connection,
Packit ae235b
     L"GET",
Packit ae235b
     winhttp_file->url.lpszUrlPath,
Packit ae235b
     NULL,
Packit ae235b
     WINHTTP_NO_REFERER,
Packit ae235b
     accept_types,
Packit ae235b
     winhttp_file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0);
Packit ae235b
Packit ae235b
  if (request == NULL)
Packit ae235b
    {
Packit ae235b
      _g_winhttp_set_error (error, GetLastError (), "GET request");
Packit ae235b
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return _g_winhttp_file_input_stream_new (winhttp_file, connection, request);
Packit ae235b
}
Packit ae235b
Packit ae235b
static GFileOutputStream *
Packit ae235b
g_winhttp_file_create (GFile             *file,
Packit ae235b
                       GFileCreateFlags   flags,
Packit ae235b
                       GCancellable      *cancellable,
Packit ae235b
                       GError           **error)
Packit ae235b
{
Packit ae235b
  GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
Packit ae235b
  HINTERNET connection;
Packit ae235b
Packit ae235b
  connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpConnect
Packit ae235b
    (G_WINHTTP_VFS (winhttp_file->vfs)->session,
Packit ae235b
     winhttp_file->url.lpszHostName,
Packit ae235b
     winhttp_file->url.nPort,
Packit ae235b
     0);
Packit ae235b
Packit ae235b
  if (connection == NULL)
Packit ae235b
    {
Packit ae235b
      _g_winhttp_set_error (error, GetLastError (), "HTTP connection");
Packit ae235b
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return _g_winhttp_file_output_stream_new (winhttp_file, connection);
Packit ae235b
}
Packit ae235b
Packit ae235b
#if 0
Packit ae235b
Packit ae235b
static GFileOutputStream *
Packit ae235b
g_winhttp_file_replace (GFile             *file,
Packit ae235b
                        const char        *etag,
Packit ae235b
                        gboolean           make_backup,
Packit ae235b
                        GFileCreateFlags   flags,
Packit ae235b
                        GCancellable      *cancellable,
Packit ae235b
                        GError           **error)
Packit ae235b
{
Packit ae235b
  /* FIXME: Implement */
Packit ae235b
Packit ae235b
  return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_winhttp_file_delete (GFile         *file,
Packit ae235b
                       GCancellable  *cancellable,
Packit ae235b
                       GError       **error)
Packit ae235b
{
Packit ae235b
  /* FIXME: Implement */
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_winhttp_file_make_directory (GFile         *file,
Packit ae235b
                               GCancellable  *cancellable,
Packit ae235b
                               GError       **error)
Packit ae235b
{
Packit ae235b
  /* FIXME: Implement */
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_winhttp_file_copy (GFile                  *source,
Packit ae235b
                     GFile                  *destination,
Packit ae235b
                     GFileCopyFlags          flags,
Packit ae235b
                     GCancellable           *cancellable,
Packit ae235b
                     GFileProgressCallback   progress_callback,
Packit ae235b
                     gpointer                progress_callback_data,
Packit ae235b
                     GError                **error)
Packit ae235b
{
Packit ae235b
  /* Fall back to default copy?? */
Packit ae235b
  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
Packit ae235b
                       "Copy not supported");
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_winhttp_file_move (GFile                  *source,
Packit ae235b
                     GFile                  *destination,
Packit ae235b
                     GFileCopyFlags          flags,
Packit ae235b
                     GCancellable           *cancellable,
Packit ae235b
                     GFileProgressCallback   progress_callback,
Packit ae235b
                     gpointer                progress_callback_data,
Packit ae235b
                     GError                **error)
Packit ae235b
{
Packit ae235b
  /* FIXME: Implement */
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
#endif
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_winhttp_file_file_iface_init (GFileIface *iface)
Packit ae235b
{
Packit ae235b
  iface->dup = g_winhttp_file_dup;
Packit ae235b
  iface->hash = g_winhttp_file_hash;
Packit ae235b
  iface->equal = g_winhttp_file_equal;
Packit ae235b
  iface->is_native = g_winhttp_file_is_native;
Packit ae235b
  iface->has_uri_scheme = g_winhttp_file_has_uri_scheme;
Packit ae235b
  iface->get_uri_scheme = g_winhttp_file_get_uri_scheme;
Packit ae235b
  iface->get_basename = g_winhttp_file_get_basename;
Packit ae235b
  iface->get_path = g_winhttp_file_get_path;
Packit ae235b
  iface->get_uri = g_winhttp_file_get_uri;
Packit ae235b
  iface->get_parse_name = g_winhttp_file_get_parse_name;
Packit ae235b
  iface->get_parent = g_winhttp_file_get_parent;
Packit ae235b
  iface->prefix_matches = g_winhttp_file_prefix_matches;
Packit ae235b
  iface->get_relative_path = g_winhttp_file_get_relative_path;
Packit ae235b
  iface->resolve_relative_path = g_winhttp_file_resolve_relative_path;
Packit ae235b
  iface->get_child_for_display_name = g_winhttp_file_get_child_for_display_name;
Packit ae235b
  iface->set_display_name = g_winhttp_file_set_display_name;
Packit ae235b
  iface->query_info = g_winhttp_file_query_info;
Packit ae235b
  iface->read_fn = g_winhttp_file_read;
Packit ae235b
  iface->create = g_winhttp_file_create;
Packit ae235b
#if 0
Packit ae235b
  iface->replace = g_winhttp_file_replace;
Packit ae235b
  iface->delete_file = g_winhttp_file_delete;
Packit ae235b
  iface->make_directory = g_winhttp_file_make_directory;
Packit ae235b
  iface->copy = g_winhttp_file_copy;
Packit ae235b
  iface->move = g_winhttp_file_move;
Packit ae235b
#endif
Packit ae235b
}