~ubuntu-branches/ubuntu/saucy/gvfs/saucy-proposed

« back to all changes in this revision

Viewing changes to daemon/gvfsbackenddav.c

Tags: upstream-0.1.7
ImportĀ upstreamĀ versionĀ 0.1.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
58
58
#include "gvfsdaemonprotocol.h"
59
59
 
60
60
#include "soup-input-stream.h"
61
 
 
 
61
#include "soup-output-stream.h"
62
62
 
63
63
struct _GVfsBackendDav
64
64
{
164
164
  if (doc == NULL)
165
165
    { 
166
166
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
167
 
                   _("Could not parse response"));
 
167
                   "%s", _("Could not parse response"));
168
168
      return NULL;
169
169
    }
170
170
 
173
173
  if (doc == NULL)
174
174
    {
175
175
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
176
 
                   _("Empty response"));
 
176
                   "%s", _("Empty response"));
177
177
      return NULL;
178
178
    }
179
179
 
180
180
  if (strcmp ((char *) (*root)->name, name))
181
181
    {
182
182
        g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
183
 
                     _("Unexpected reply from server"));
 
183
                     "%s", _("Unexpected reply from server"));
184
184
      return NULL;
185
185
    }
186
186
 
531
531
static void
532
532
soup_authenticate (SoupSession *session,
533
533
                   SoupMessage *msg,
534
 
                   SoupAuth    *auth,
 
534
                   SoupAuth    *auth,
535
535
                   gboolean     retrying,
536
536
                   gpointer     user_data)
537
537
{
837
837
 
838
838
  /* RFC 4437 */
839
839
  if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS)
840
 
      redirect_header = "F";
 
840
    redirect_header = "F";
841
841
  else
842
 
      redirect_header = "T";
 
842
    redirect_header = "T";
843
843
 
844
844
  soup_message_headers_append (msg->request_headers,
845
 
                           "Apply-To-Redirect-Ref", redirect_header);
 
845
                               "Apply-To-Redirect-Ref", redirect_header);
846
846
 
847
847
  soup_message_set_request (msg, "application/xml",
848
848
                            SOUP_MEMORY_TAKE,
971
971
/* ************************************************************************* */
972
972
/*  */
973
973
 
 
974
/* *** create () *** */
 
975
static void
 
976
try_create_tested_existence (SoupSession *session, SoupMessage *msg,
 
977
                             gpointer user_data)
 
978
{
 
979
  GVfsJob *job = G_VFS_JOB (user_data);
 
980
  GVfsBackendHttp *op_backend = job->backend_data;
 
981
  GOutputStream   *stream;
 
982
  SoupMessage     *put_msg;
 
983
 
 
984
  if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
 
985
    {
 
986
      g_vfs_job_failed (job,
 
987
                        G_IO_ERROR,
 
988
                        G_IO_ERROR_EXISTS,
 
989
                        _("Target file already exists"));
 
990
      return;
 
991
    }
 
992
  /* FIXME: other errors */
 
993
 
 
994
  put_msg = message_new_from_uri ("PUT", soup_message_get_uri (msg));
 
995
 
 
996
  soup_message_headers_append (put_msg->request_headers, "If-None-Match", "*");
 
997
  stream = soup_output_stream_new (op_backend->session, put_msg, -1);
 
998
  g_object_unref (put_msg);
 
999
 
 
1000
  g_vfs_job_open_for_write_set_handle (G_VFS_JOB_OPEN_FOR_WRITE (job), stream);
 
1001
  g_vfs_job_succeeded (job);
 
1002
}  
 
1003
 
 
1004
static gboolean
 
1005
try_create (GVfsBackend *backend,
 
1006
            GVfsJobOpenForWrite *job,
 
1007
            const char *filename,
 
1008
            GFileCreateFlags flags)
 
1009
{
 
1010
  GVfsBackendHttp *op_backend;
 
1011
  SoupMessage     *msg;
 
1012
 
 
1013
  /* FIXME: if SoupOutputStream supported chunked requests, we could
 
1014
   * use a PUT with "If-None-Match: *" and "Expect: 100-continue"
 
1015
   */
 
1016
 
 
1017
  op_backend = G_VFS_BACKEND_HTTP (backend);
 
1018
 
 
1019
  msg = message_new_from_filename (backend, "HEAD", filename);
 
1020
 
 
1021
  g_vfs_job_set_backend_data (G_VFS_JOB (job), op_backend, NULL);
 
1022
  soup_session_queue_message (op_backend->session, msg,
 
1023
                              try_create_tested_existence, job);
 
1024
  return TRUE;
 
1025
}
 
1026
 
 
1027
/* *** replace () *** */
 
1028
static void
 
1029
open_for_replace_succeeded (GVfsBackendHttp *op_backend, GVfsJob *job,
 
1030
                            SoupURI *uri, const char *etag)
 
1031
{
 
1032
  SoupMessage     *put_msg;
 
1033
  GOutputStream   *stream;
 
1034
 
 
1035
  put_msg = message_new_from_uri (SOUP_METHOD_PUT, uri);
 
1036
 
 
1037
  if (etag)
 
1038
    soup_message_headers_append (put_msg->request_headers, "If-Match", etag);
 
1039
 
 
1040
  stream = soup_output_stream_new (op_backend->session, put_msg, -1);
 
1041
  g_object_unref (put_msg);
 
1042
 
 
1043
  g_vfs_job_open_for_write_set_handle (G_VFS_JOB_OPEN_FOR_WRITE (job), stream);
 
1044
  g_vfs_job_succeeded (job);
 
1045
}
 
1046
 
 
1047
static void
 
1048
try_replace_checked_etag (SoupSession *session, SoupMessage *msg,
 
1049
                          gpointer user_data)
 
1050
{
 
1051
  GVfsJob *job = G_VFS_JOB (user_data);
 
1052
  GVfsBackendHttp *op_backend = job->backend_data;
 
1053
 
 
1054
  if (msg->status_code == SOUP_STATUS_PRECONDITION_FAILED)
 
1055
    {
 
1056
      g_vfs_job_failed (G_VFS_JOB (job),
 
1057
                        G_IO_ERROR,
 
1058
                        G_IO_ERROR_WRONG_ETAG,
 
1059
                        _("The file was externally modified"));
 
1060
      return;
 
1061
    }
 
1062
  /* FIXME: other errors */
 
1063
 
 
1064
  open_for_replace_succeeded (op_backend, job, soup_message_get_uri (msg),
 
1065
                              soup_message_headers_get (msg->request_headers, "If-Match"));
 
1066
}  
 
1067
 
 
1068
static gboolean
 
1069
try_replace (GVfsBackend *backend,
 
1070
             GVfsJobOpenForWrite *job,
 
1071
             const char *filename,
 
1072
             const char *etag,
 
1073
             gboolean make_backup,
 
1074
             GFileCreateFlags flags)
 
1075
{
 
1076
  GVfsBackendHttp *op_backend;
 
1077
  SoupURI         *uri;
 
1078
 
 
1079
  /* FIXME: if SoupOutputStream supported chunked requests, we could
 
1080
   * use a PUT with "If-Match: ..." and "Expect: 100-continue"
 
1081
   */
 
1082
 
 
1083
  op_backend = G_VFS_BACKEND_HTTP (backend);
 
1084
 
 
1085
  if (make_backup)
 
1086
    {
 
1087
      g_vfs_job_failed (G_VFS_JOB (job),
 
1088
                        G_IO_ERROR,
 
1089
                        G_IO_ERROR_CANT_CREATE_BACKUP,
 
1090
                        _("Backup file creation failed"));
 
1091
      return TRUE;
 
1092
    }
 
1093
 
 
1094
 
 
1095
 
 
1096
  uri = g_vfs_backend_uri_for_filename (backend, filename);
 
1097
 
 
1098
  if (etag)
 
1099
    {
 
1100
      SoupMessage *msg;
 
1101
 
 
1102
      msg = soup_message_new_from_uri (SOUP_METHOD_HEAD, uri);
 
1103
      soup_uri_free (uri);
 
1104
      soup_message_headers_append (msg->request_headers, "User-Agent", "gvfs/" VERSION);
 
1105
      soup_message_headers_append (msg->request_headers, "If-Match", etag);
 
1106
 
 
1107
      g_vfs_job_set_backend_data (G_VFS_JOB (job), op_backend, NULL);
 
1108
      soup_session_queue_message (op_backend->session, msg,
 
1109
                                  try_replace_checked_etag, job);
 
1110
      return TRUE;
 
1111
    }
 
1112
 
 
1113
  open_for_replace_succeeded (op_backend, G_VFS_JOB (job), uri, NULL);
 
1114
  soup_uri_free (uri);
 
1115
  return TRUE;
 
1116
}
 
1117
 
 
1118
/* *** write () *** */
 
1119
static void
 
1120
write_ready (GObject      *source_object,
 
1121
             GAsyncResult *result,
 
1122
             gpointer      user_data)
 
1123
{
 
1124
  GOutputStream *stream;
 
1125
  GVfsJob       *job;
 
1126
  GError        *error;
 
1127
  gssize         nwrote;
 
1128
 
 
1129
  stream = G_OUTPUT_STREAM (source_object); 
 
1130
  error  = NULL;
 
1131
  job    = G_VFS_JOB (user_data);
 
1132
 
 
1133
  nwrote = g_output_stream_write_finish (stream, result, &error);
 
1134
 
 
1135
  if (nwrote < 0)
 
1136
   {
 
1137
     g_vfs_job_failed (G_VFS_JOB (job),
 
1138
                       error->domain,
 
1139
                       error->code,
 
1140
                       error->message);
 
1141
 
 
1142
     g_error_free (error);
 
1143
     return;
 
1144
   }
 
1145
 
 
1146
  g_vfs_job_write_set_written_size (G_VFS_JOB_WRITE (job), nwrote);
 
1147
  g_vfs_job_succeeded (job);
 
1148
}
 
1149
 
 
1150
static gboolean
 
1151
try_write (GVfsBackend *backend,
 
1152
           GVfsJobWrite *job,
 
1153
           GVfsBackendHandle handle,
 
1154
           char *buffer,
 
1155
           gsize buffer_size)
 
1156
{
 
1157
  GVfsBackendHttp *op_backend;
 
1158
  GOutputStream   *stream;
 
1159
 
 
1160
  op_backend = G_VFS_BACKEND_HTTP (backend);
 
1161
  stream = G_OUTPUT_STREAM (handle);
 
1162
 
 
1163
  g_output_stream_write_async (stream,
 
1164
                               buffer,
 
1165
                               buffer_size,
 
1166
                               G_PRIORITY_DEFAULT,
 
1167
                               G_VFS_JOB (job)->cancellable,
 
1168
                               write_ready,
 
1169
                               job);
 
1170
  return TRUE;
 
1171
}
 
1172
 
 
1173
/* *** close_write () *** */
 
1174
static void
 
1175
close_write_ready (GObject      *source_object,
 
1176
                   GAsyncResult *result,
 
1177
                   gpointer      user_data)
 
1178
{
 
1179
  GOutputStream *stream;
 
1180
  GVfsJob       *job;
 
1181
  GError        *error;
 
1182
  gboolean       res;
 
1183
 
 
1184
  job = G_VFS_JOB (user_data);
 
1185
  stream = G_OUTPUT_STREAM (source_object);
 
1186
  res = g_output_stream_close_finish (stream,
 
1187
                                      result,
 
1188
                                      &error);
 
1189
  if (res == FALSE)
 
1190
    {
 
1191
      g_vfs_job_failed (G_VFS_JOB (job),
 
1192
                        error->domain,
 
1193
                        error->code,
 
1194
                        error->message);
 
1195
 
 
1196
      g_error_free (error);
 
1197
    }
 
1198
  else
 
1199
    g_vfs_job_succeeded (job);
 
1200
 
 
1201
  g_object_unref (stream);
 
1202
}
 
1203
 
 
1204
static gboolean
 
1205
try_close_write (GVfsBackend *backend,
 
1206
                 GVfsJobCloseWrite *job,
 
1207
                 GVfsBackendHandle handle)
 
1208
{
 
1209
  GVfsBackendHttp *op_backend;
 
1210
  GOutputStream   *stream;
 
1211
 
 
1212
  op_backend = G_VFS_BACKEND_HTTP (backend);
 
1213
  stream = G_OUTPUT_STREAM (handle);
 
1214
 
 
1215
  g_output_stream_close_async (stream,
 
1216
                               G_PRIORITY_DEFAULT,
 
1217
                               G_VFS_JOB (job)->cancellable,
 
1218
                               close_write_ready,
 
1219
                               job);
 
1220
 
 
1221
  return TRUE;
 
1222
}
 
1223
 
 
1224
/* ************************************************************************* */
 
1225
/*  */
 
1226
 
974
1227
static void
975
1228
g_vfs_backend_dav_class_init (GVfsBackendDavClass *klass)
976
1229
{
981
1234
  gobject_class->finalize  = g_vfs_backend_dav_finalize;
982
1235
 
983
1236
  backend_class = G_VFS_BACKEND_CLASS (klass); 
 
1237
 
984
1238
  backend_class->try_mount         = try_mount;
985
1239
  backend_class->try_query_info    = try_query_info;
986
1240
  backend_class->try_enumerate     = try_enumerate;
 
1241
  backend_class->try_create        = try_create;
 
1242
  backend_class->try_replace       = try_replace;
 
1243
  backend_class->try_write         = try_write;
 
1244
  backend_class->try_close_write   = try_close_write;
 
1245
 
987
1246
}