Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(125)

Delta Between Two Patch Sets: Src/GoogleApis/Apis/[Media]/Upload/ResumableUpload.cs

Issue 13412046: Reimplement OAuth2 library - Step 1 (Closed) Base URL: https://google-api-dotnet-client.googlecode.com/hg/
Left Patch Set: self review Created 10 years, 10 months ago
Right Patch Set: minor Created 10 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 /* 1 /*
2 Copyright 2012 Google Inc 2 Copyright 2012 Google Inc
3 3
4 Licensed under the Apache License, Version 2.0 (the "License"); 4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License. 5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at 6 You may obtain a copy of the License at
7 7
8 http://www.apache.org/licenses/LICENSE-2.0 8 http://www.apache.org/licenses/LICENSE-2.0
9 9
10 Unless required by applicable law or agreed to in writing, software 10 Unless required by applicable law or agreed to in writing, software
(...skipping 27 matching lines...) Expand all
38 /// See: https://developers.google.com/drive/manage-uploads#resumable for mo re information on the protocol. 38 /// See: https://developers.google.com/drive/manage-uploads#resumable for mo re information on the protocol.
39 /// </remarks> 39 /// </remarks>
40 /// <typeparam name="TRequest"> 40 /// <typeparam name="TRequest">
41 /// The type of the body of this request. Generally this should be the metad ata related to the content to be· 41 /// The type of the body of this request. Generally this should be the metad ata related to the content to be·
42 /// uploaded. Must be serializable to/from JSON. 42 /// uploaded. Must be serializable to/from JSON.
43 /// </typeparam> 43 /// </typeparam>
44 public class ResumableUpload<TRequest> 44 public class ResumableUpload<TRequest>
45 { 45 {
46 #region Constants 46 #region Constants
47 47
48 /// <summary> The class logger. </summary> 48 /// <summary>The class logger.</summary>
49 private static readonly ILogger logger = ApplicationContext.Logger.ForTy pe<ResumableUpload<TRequest>>(); 49 private static readonly ILogger logger = ApplicationContext.Logger.ForTy pe<ResumableUpload<TRequest>>();
50 50
51 private const int KB = 0x400; 51 private const int KB = 0x400;
52 private const int MB = 0x100000; 52 private const int MB = 0x100000;
53 53
54 /// <summary> Minimum chunk size (except the last one). Default value is 256*KB. </summary> 54 /// <summary>Minimum chunk size (except the last one). Default value is 256*KB.</summary>
55 public const int MinimumChunkSize = 256 * KB; 55 public const int MinimumChunkSize = 256 * KB;
56 56
57 /// <summary> Default chunk size. Default value is 10*MB. </summary> 57 /// <summary>Default chunk size. Default value is 10*MB.</summary>
58 public const int DefaultChunkSize = 10 * MB; 58 public const int DefaultChunkSize = 10 * MB;
59 59
60 /// <summary> 60 /// <summary>
61 /// Defines how many bytes are read from the input stream in each stream read action.· 61 /// Defines how many bytes are read from the input stream in each stream read action.·
62 /// The read will continue until we read <see cref="MinimumChunkSize"/> or we reached the end of the stream. 62 /// The read will continue until we read <see cref="MinimumChunkSize"/> or we reached the end of the stream.
63 /// </summary> 63 /// </summary>
64 internal int BufferSize = 4 * KB; 64 internal int BufferSize = 4 * KB;
65 65
66 /// <summary> Indicates the stream's size is unknown. </summary> 66 /// <summary>Indicates the stream's size is unknown.</summary>
67 private const int UnknownSize = -1; 67 private const int UnknownSize = -1;
68 68
69 /// <summary> The mime type for the encoded JSON body. </summary> 69 /// <summary>The mime type for the encoded JSON body.</summary>
70 private const string JsonMimeType = "application/json; charset=UTF-8"; 70 private const string JsonMimeType = "application/json; charset=UTF-8";
71 71
72 /// <summary> Payload description headers, describing the content itself . </summary> 72 /// <summary>Payload description headers, describing the content itself. </summary>
73 private const string PayloadContentTypeHeader = "X-Upload-Content-Type"; 73 private const string PayloadContentTypeHeader = "X-Upload-Content-Type";
74 74
75 /// <summary> Payload description headers, describing the content itself . </summary> 75 /// <summary>Payload description headers, describing the content itself. </summary>
76 private const string PayloadContentLengthHeader = "X-Upload-Content-Leng th"; 76 private const string PayloadContentLengthHeader = "X-Upload-Content-Leng th";
77 77
78 /// <summary> Specify the type of this upload (this class supports resum able only). </summary> 78 /// <summary>Specify the type of this upload (this class supports resuma ble only).</summary>
79 private const string UploadType = "uploadType"; 79 private const string UploadType = "uploadType";
80 80
81 /// <summary> The uploadType parameter value for resumable uploads. </su mmary> 81 /// <summary>The uploadType parameter value for resumable uploads.</summ ary>
82 private const string Resumable = "resumable"; 82 private const string Resumable = "resumable";
83 83
84 /// <summary> Content-Range header value for the body upload of zero len gth files. </summary> 84 /// <summary>Content-Range header value for the body upload of zero leng th files.</summary>
85 private const string ZeroByteContentRangeHeader = "bytes */0"; 85 private const string ZeroByteContentRangeHeader = "bytes */0";
86 86
87 #endregion // Constants 87 #endregion // Constants
88 88
89 #region Construction 89 #region Construction
90 90
91 /// <summary> 91 /// <summary>
92 /// Create a resumable upload instance with the required parameters. 92 /// Create a resumable upload instance with the required parameters.
93 /// </summary> 93 /// </summary>
94 /// <param name="service">The client service.</param> 94 /// <param name="service">The client service.</param>
(...skipping 19 matching lines...) Expand all
114 this.Path = path; 114 this.Path = path;
115 this.HttpMethod = httpMethod; 115 this.HttpMethod = httpMethod;
116 this.ContentStream = contentStream; 116 this.ContentStream = contentStream;
117 this.ContentType = contentType; 117 this.ContentType = contentType;
118 } 118 }
119 119
120 #endregion // Construction 120 #endregion // Construction
121 121
122 #region Properties 122 #region Properties
123 123
124 /// <summary> Gets or sets the service. </summary> 124 /// <summary>Gets or sets the service.</summary>
125 public IClientService Service { get; private set; } 125 public IClientService Service { get; private set; }
126 126
127 /// <summary> 127 /// <summary>
128 /// Gets or sets the path of the method (combined with <see cref="IClien tService.BaseUri"/>) to produce· 128 /// Gets or sets the path of the method (combined with <see cref="IClien tService.BaseUri"/>) to produce·
129 /// absolute Uri.· 129 /// absolute Uri.·
130 /// </summary> 130 /// </summary>
131 public string Path { get; private set; } 131 public string Path { get; private set; }
132 132
133 /// <summary> Gets or sets the HTTP method of this upload (used to initi alize the upload). </summary> 133 /// <summary>Gets or sets the HTTP method of this upload (used to initia lize the upload).</summary>
134 public string HttpMethod { get; private set; } 134 public string HttpMethod { get; private set; }
135 135
136 /// <summary> Gets or sets the stream to upload. </summary> 136 /// <summary>Gets or sets the stream to upload.</summary>
137 public Stream ContentStream { get; private set; } 137 public Stream ContentStream { get; private set; }
138 138
139 /// <summary> Gets or sets the stream's Content-Type. </summary> 139 /// <summary>Gets or sets the stream's Content-Type.</summary>
140 public string ContentType { get; private set; } 140 public string ContentType { get; private set; }
141 141
142 /// <summary> 142 /// <summary>
143 /// Gets or sets the length of the steam. Will be <see cref="UnknownSize " /> if the media content length is· 143 /// Gets or sets the length of the steam. Will be <see cref="UnknownSize " /> if the media content length is·
144 /// unknown.· 144 /// unknown.·
145 /// </summary> 145 /// </summary>
146 private long StreamLength { get; set; } 146 private long StreamLength { get; set; }
147 147
148 /// <summary> 148 /// <summary>
149 /// Gets or sets the content of the last buffer request to the server or <c>null</c> for none. It is used when· 149 /// Gets or sets the content of the last buffer request to the server or <c>null</c> for none. It is used when·
150 /// the media content length is unknown, for resending it in case of ser ver error. 150 /// the media content length is unknown, for resending it in case of ser ver error.
151 /// </summary> 151 /// </summary>
152 private byte[] LastMediaRequest { get; set; } 152 private byte[] LastMediaRequest { get; set; }
153 153
154 /// <summary> Gets or sets cached byte which indicates if end of stream has been reached. </summary> 154 /// <summary>Gets or sets cached byte which indicates if end of stream h as been reached.</summary>
155 private byte[] CachedByte { get; set; } 155 private byte[] CachedByte { get; set; }
156 156
157 /// <summary> Gets or sets the last request length. </summary> 157 /// <summary>Gets or sets the last request length.</summary>
158 private int LastMediaLength { get; set; } 158 private int LastMediaLength { get; set; }
159 159
160 /// <summary> 160 /// <summary>
161 /// Gets or sets the resumable session Uri.· 161 /// Gets or sets the resumable session Uri.·
162 /// See https://developers.google.com/drive/manage-uploads#save-session- uri" for more details. 162 /// See https://developers.google.com/drive/manage-uploads#save-session- uri" for more details.
163 /// </summary> 163 /// </summary>
164 private Uri UploadUri { get; set; } 164 private Uri UploadUri { get; set; }
165 165
166 /// <summary> Gets or sets the amount of bytes the server had received s o far. </summary> 166 /// <summary>Gets or sets the amount of bytes the server had received so far.</summary>
167 private long BytesServerReceived { get; set; } 167 private long BytesServerReceived { get; set; }
168 168
169 /// <summary> Gets or sets the amount of bytes the client had sent so fa r. </summary> 169 /// <summary>Gets or sets the amount of bytes the client had sent so far .</summary>
170 private long BytesClientSent { get; set; } 170 private long BytesClientSent { get; set; }
171 171
172 /// <summary> Gets or sets the body of this request. </summary> 172 /// <summary>Gets or sets the body of this request.</summary>
173 public TRequest Body { get; set; } 173 public TRequest Body { get; set; }
174 174
175 [VisibleForTestOnly] 175 [VisibleForTestOnly]
176 internal int chunkSize = DefaultChunkSize; 176 internal int chunkSize = DefaultChunkSize;
177 177
178 /// <summary> 178 /// <summary>
179 /// Gets or sets the size of each chunk sent to the server. 179 /// Gets or sets the size of each chunk sent to the server.
180 /// Chunks (except the last chunk) must be a multiple of <see cref="Mini mumChunkSize"/> to be compatible with· 180 /// Chunks (except the last chunk) must be a multiple of <see cref="Mini mumChunkSize"/> to be compatible with·
181 /// Google upload servers. 181 /// Google upload servers.
182 /// </summary> 182 /// </summary>
183 public int ChunkSize 183 public int ChunkSize
184 { 184 {
185 get { return chunkSize; } 185 get { return chunkSize; }
186 set 186 set
187 { 187 {
188 if (value < MinimumChunkSize) 188 if (value < MinimumChunkSize)
189 { 189 {
190 throw new ArgumentOutOfRangeException("ChunkSize"); 190 throw new ArgumentOutOfRangeException("ChunkSize");
191 } 191 }
192 chunkSize = value; 192 chunkSize = value;
193 } 193 }
194 } 194 }
195 195
196 #endregion // Properties 196 #endregion // Properties
197 197
198 #region Events 198 #region Events
199 199
200 /// <summary> Event called whenever the progress of the upload changes. </summary> 200 /// <summary>Event called whenever the progress of the upload changes.</ summary>
201 public event Action<IUploadProgress> ProgressChanged; 201 public event Action<IUploadProgress> ProgressChanged;
202 202
203 #endregion //Events 203 #endregion //Events
204 204
205 #region Error handling (Exception and 5xx) 205 #region Error handling (Exception and 5xx)
206 206
207 /// <summary> 207 /// <summary>
208 /// Callback class that is invoked on abnormal response or an exception. 208 /// Callback class that is invoked on abnormal response or an exception.
209 /// This class changes the request to query the current status of the up load in order to find how many bytes·· 209 /// This class changes the request to query the current status of the up load in order to find how many bytes··
210 /// were successfully uploaded before the error occurred. 210 /// were successfully uploaded before the error occurred.
211 /// See https://developers.google.com/drive/manage-uploads#resume-upload for more details. 211 /// See https://developers.google.com/drive/manage-uploads#resume-upload for more details.
212 /// </summary> 212 /// </summary>
213 class ServerErrorCallback : IHttpUnsuccessfulResponseHandler, IHttpExcep tionHandler, IDisposable 213 class ServerErrorCallback : IHttpUnsuccessfulResponseHandler, IHttpExcep tionHandler, IDisposable
214 { 214 {
215 private ResumableUpload<TRequest> Owner { get; set; } 215 private ResumableUpload<TRequest> Owner { get; set; }
216 216
217 /// <summary> 217 /// <summary>
218 /// Constructs a new callback and register it as unsuccessful respon se handler and exception handler on the· 218 /// Constructs a new callback and register it as unsuccessful respon se handler and exception handler on the·
219 /// configurable message handler. 219 /// configurable message handler.
220 /// </summary> 220 /// </summary>
221 public ServerErrorCallback(ResumableUpload<TRequest> resumable) 221 public ServerErrorCallback(ResumableUpload<TRequest> resumable)
222 { 222 {
223 this.Owner = resumable; 223 this.Owner = resumable;
224 Owner.Service.HttpClient.MessageHandler.UnsuccessfulResponseHand lers.Add(this); 224 Owner.Service.HttpClient.MessageHandler.UnsuccessfulResponseHand lers.Add(this);
225 Owner.Service.HttpClient.MessageHandler.ExceptionHandlers.Add(th is); 225 Owner.Service.HttpClient.MessageHandler.ExceptionHandlers.Add(th is);
226 } 226 }
227 227
(...skipping 20 matching lines...) Expand all
248 public Task<bool> HandleExceptionAsync(HandleExceptionArgs args) 248 public Task<bool> HandleExceptionAsync(HandleExceptionArgs args)
249 { 249 {
250 var result = args.SupportsRetry && !args.CancellationToken.IsCan cellationRequested && 250 var result = args.SupportsRetry && !args.CancellationToken.IsCan cellationRequested &&
251 args.Request.RequestUri.Equals(Owner.UploadUri) ? OnServerEr ror(args.Request) : false; 251 args.Request.RequestUri.Equals(Owner.UploadUri) ? OnServerEr ror(args.Request) : false;
252 252
253 TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>( ); 253 TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>( );
254 tcs.SetResult(result); 254 tcs.SetResult(result);
255 return tcs.Task; 255 return tcs.Task;
256 } 256 }
257 257
258 /// <summary> Changes the request in order to resume the interrupted upload. </summary> 258 /// <summary>Changes the request in order to resume the interrupted upload.</summary>
259 private bool OnServerError(HttpRequestMessage request) 259 private bool OnServerError(HttpRequestMessage request)
260 { 260 {
261 // clear all headers and set Content-Range and Content-Length he aders 261 // clear all headers and set Content-Range and Content-Length he aders
262 var range = String.Format("bytes */{0}", Owner.StreamLength < 0 ? "*" : Owner.StreamLength.ToString()); 262 var range = String.Format("bytes */{0}", Owner.StreamLength < 0 ? "*" : Owner.StreamLength.ToString());
263 request.Headers.Clear(); 263 request.Headers.Clear();
264 request.Method = System.Net.Http.HttpMethod.Put; 264 request.Method = System.Net.Http.HttpMethod.Put;
265 request.SetEmptyContent().Headers.Add("Content-Range", range); 265 request.SetEmptyContent().Headers.Add("Content-Range", range);
266 return true; 266 return true;
267 } 267 }
268 268
269 public void Dispose() 269 public void Dispose()
270 { 270 {
271 Owner.Service.HttpClient.MessageHandler.UnsuccessfulResponseHand lers.Remove(this); 271 Owner.Service.HttpClient.MessageHandler.UnsuccessfulResponseHand lers.Remove(this);
272 Owner.Service.HttpClient.MessageHandler.ExceptionHandlers.Remove (this); 272 Owner.Service.HttpClient.MessageHandler.ExceptionHandlers.Remove (this);
273 } 273 }
274 } 274 }
275 275
276 #endregion 276 #endregion
277 277
278 #region Progress Monitoring 278 #region Progress Monitoring
279 279
280 /// <summary> Class that communicates the progress of resumable uploads to a container. </summary> 280 /// <summary>Class that communicates the progress of resumable uploads t o a container.</summary>
281 private class ResumableUploadProgress : IUploadProgress 281 private class ResumableUploadProgress : IUploadProgress
282 { 282 {
283 /// <summary> 283 /// <summary>
284 /// Create a ResumableUploadProgress instance. 284 /// Create a ResumableUploadProgress instance.
285 /// </summary> 285 /// </summary>
286 /// <param name="status">The status of the upload.</param> 286 /// <param name="status">The status of the upload.</param>
287 /// <param name="bytesSent">The number of bytes sent so far.</param> 287 /// <param name="bytesSent">The number of bytes sent so far.</param>
288 public ResumableUploadProgress(UploadStatus status, long bytesSent) 288 public ResumableUploadProgress(UploadStatus status, long bytesSent)
289 { 289 {
290 Status = status; 290 Status = status;
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 } 376 }
377 catch (Exception ex) 377 catch (Exception ex)
378 { 378 {
379 logger.Error(ex, "MediaUpload[{0}] - Exception occurred while up loading media", UploadUri); 379 logger.Error(ex, "MediaUpload[{0}] - Exception occurred while up loading media", UploadUri);
380 UpdateProgress(new ResumableUploadProgress(ex, BytesServerReceiv ed)); 380 UpdateProgress(new ResumableUploadProgress(ex, BytesServerReceiv ed));
381 } 381 }
382 382
383 return Progress; 383 return Progress;
384 } 384 }
385 385
386 /// <summary> Uploads the content asynchronously to the server.</summary > 386 /// <summary>Uploads the content asynchronously to the server.</summary>
387 /// <remarks> 387 /// <remarks>
388 /// In case the upload fails the task will not be completed. In that cas e the task's· 388 /// In case the upload fails the task will not be completed. In that cas e the task's·
389 /// <seealso cref="System.Threading.Tasks.Task.Exception"/> property wil l bet set, or its· 389 /// <seealso cref="System.Threading.Tasks.Task.Exception"/> property wil l bet set, or its·
390 /// <seealso cref="System.Threading.Tasks.Task.IsCanceled"/> property wi ll be true. 390 /// <seealso cref="System.Threading.Tasks.Task.IsCanceled"/> property wi ll be true.
391 /// </remarks> 391 /// </remarks>
392 public Task<IUploadProgress> UploadAsync() 392 public Task<IUploadProgress> UploadAsync()
393 { 393 {
394 return UploadAsync(CancellationToken.None); 394 return UploadAsync(CancellationToken.None);
395 } 395 }
396 396
397 /// <summary> Uploads the content asynchronously to the server.</summary > 397 /// <summary>Uploads the content asynchronously to the server.</summary>
398 /// <param name="cancellationToken">The cancellation token to cancel a r equest in the middle.</param> 398 /// <param name="cancellationToken">The cancellation token to cancel a r equest in the middle.</param>
399 public Task<IUploadProgress> UploadAsync(CancellationToken cancellationT oken) 399 public Task<IUploadProgress> UploadAsync(CancellationToken cancellationT oken)
400 { 400 {
401 TaskCompletionSource<IUploadProgress> tcs = new TaskCompletionSource <IUploadProgress>(); 401 TaskCompletionSource<IUploadProgress> tcs = new TaskCompletionSource <IUploadProgress>();
402 Task.Factory.StartNew(async () => 402 Task.Factory.StartNew(async () =>
403 { 403 {
404 try 404 try
405 { 405 {
406 var response = await Upload(cancellationToken).ConfigureAwai t(false); 406 var response = await Upload(cancellationToken).ConfigureAwai t(false);
407 if (response.Exception != null) 407 if (response.Exception != null)
(...skipping 29 matching lines...) Expand all
437 } 437 }
438 438
439 /// <summary> 439 /// <summary>
440 /// Process a response from the final upload chunk call. 440 /// Process a response from the final upload chunk call.
441 /// </summary> 441 /// </summary>
442 /// <param name="httpResponse">The response body from the final uploaded chunk.</param> 442 /// <param name="httpResponse">The response body from the final uploaded chunk.</param>
443 protected virtual void ProcessResponse(HttpResponseMessage httpResponse) 443 protected virtual void ProcessResponse(HttpResponseMessage httpResponse)
444 { 444 {
445 } 445 }
446 446
447 /// <summary> 447 /// <summary>
448 /// Uploads the next chunk of data to the server. 448 /// Uploads the next chunk of data to the server.
449 /// </summary> 449 /// </summary>
450 /// <returns>· 450 /// <returns>·
451 /// <c>True</c> if the entire media has been completely uploaded. 451 /// <c>True</c> if the entire media has been completely uploaded.
452 /// </returns> 452 /// </returns>
453 protected async Task<bool> SendNextChunk(Stream stream, CancellationToke n cancellationToken) 453 protected async Task<bool> SendNextChunk(Stream stream, CancellationToke n cancellationToken)
454 { 454 {
455 cancellationToken.ThrowIfCancellationRequested(); 455 cancellationToken.ThrowIfCancellationRequested();
456 456
457 HttpRequestMessage request = new RequestBuilder() 457 HttpRequestMessage request = new RequestBuilder()
(...skipping 28 matching lines...) Expand all
486 // The upload protocol uses 308 to indicate that there is more d ata expected from the server. 486 // The upload protocol uses 308 to indicate that there is more d ata expected from the server.
487 BytesServerReceived = GetNextByte(response.Headers.GetValues("Ra nge").First()); 487 BytesServerReceived = GetNextByte(response.Headers.GetValues("Ra nge").First());
488 logger.Debug("MediaUpload[{0}] - {1} Bytes were sent successfull y", UploadUri, BytesServerReceived); 488 logger.Debug("MediaUpload[{0}] - {1} Bytes were sent successfull y", UploadUri, BytesServerReceived);
489 return false; 489 return false;
490 } 490 }
491 491
492 var error = await Service.DeserializeError(response).ConfigureAwait( false); 492 var error = await Service.DeserializeError(response).ConfigureAwait( false);
493 throw new GoogleApiException(Service.Name, error.ToString()); 493 throw new GoogleApiException(Service.Name, error.ToString());
494 } 494 }
495 495
496 /// <summary> A callback when the media was uploaded successfully. </sum mary> 496 /// <summary>A callback when the media was uploaded successfully.</summa ry>
497 private void MediaCompleted(HttpResponseMessage response) 497 private void MediaCompleted(HttpResponseMessage response)
498 { 498 {
499 logger.Debug("MediaUpload[{0}] - media was uploaded successfully", U ploadUri); 499 logger.Debug("MediaUpload[{0}] - media was uploaded successfully", U ploadUri);
500 ProcessResponse(response); 500 ProcessResponse(response);
501 BytesServerReceived = LastMediaLength; 501 BytesServerReceived = LastMediaLength;
502 502
503 // clear the last request byte array 503 // clear the last request byte array
504 LastMediaRequest = null; 504 LastMediaRequest = null;
505 } 505 }
506 506
507 /// <summary> Prepares the given request with the next chunk in case the steam length is unknown. </summary> 507 /// <summary>Prepares the given request with the next chunk in case the steam length is unknown.</summary>
508 private void PrepareNextChunkUnknownSize(HttpRequestMessage request, Str eam stream, 508 private void PrepareNextChunkUnknownSize(HttpRequestMessage request, Str eam stream,
509 CancellationToken cancellationToken) 509 CancellationToken cancellationToken)
510 { 510 {
511 // We save the current request, so we would be able to resend those bytes in case of a server error 511 // We save the current request, so we would be able to resend those bytes in case of a server error
512 if (LastMediaRequest == null) 512 if (LastMediaRequest == null)
513 { 513 {
514 LastMediaRequest = new byte[ChunkSize]; 514 LastMediaRequest = new byte[ChunkSize];
515 } 515 }
516 516
517 LastMediaLength = 0; 517 LastMediaLength = 0;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
565 CachedByte = null; 565 CachedByte = null;
566 } 566 }
567 } 567 }
568 568
569 // set Content-Length and Content-Range 569 // set Content-Length and Content-Range
570 var byteArrayContent = new ByteArrayContent(LastMediaRequest, 0, Las tMediaLength); 570 var byteArrayContent = new ByteArrayContent(LastMediaRequest, 0, Las tMediaLength);
571 byteArrayContent.Headers.Add("Content-Range", GetContentRangeHeader( BytesServerReceived, LastMediaLength)); 571 byteArrayContent.Headers.Add("Content-Range", GetContentRangeHeader( BytesServerReceived, LastMediaLength));
572 request.Content = byteArrayContent; 572 request.Content = byteArrayContent;
573 } 573 }
574 574
575 /// <summary> Prepares the given request with the next chunk in case the steam length is known. </summary> 575 /// <summary>Prepares the given request with the next chunk in case the steam length is known.</summary>
576 private void PrepareNextChunkKnownSize(HttpRequestMessage request, Strea m stream, 576 private void PrepareNextChunkKnownSize(HttpRequestMessage request, Strea m stream,
577 CancellationToken cancellationToken) 577 CancellationToken cancellationToken)
578 { 578 {
579 int chunkSize = (int)Math.Min(StreamLength - BytesServerReceived, (l ong)ChunkSize); 579 int chunkSize = (int)Math.Min(StreamLength - BytesServerReceived, (l ong)ChunkSize);
580 580
581 // stream length is known and it supports seek and position operatio ns. 581 // stream length is known and it supports seek and position operatio ns.
582 // We can change the stream position and read bytes from the last po int 582 // We can change the stream position and read bytes from the last po int
583 byte[] buffer = new byte[Math.Min(chunkSize, BufferSize)]; 583 byte[] buffer = new byte[Math.Min(chunkSize, BufferSize)];
584 584
585 // if the number of bytes received by the server isn't equal to the amount of bytes the client sent, we· 585 // if the number of bytes received by the server isn't equal to the amount of bytes the client sent, we·
(...skipping 18 matching lines...) Expand all
604 } 604 }
605 605
606 // set the stream position to beginning and wrap it with stream cont ent 606 // set the stream position to beginning and wrap it with stream cont ent
607 ms.Position = 0; 607 ms.Position = 0;
608 request.Content = new StreamContent(ms); 608 request.Content = new StreamContent(ms);
609 request.Content.Headers.Add("Content-Range", GetContentRangeHeader(B ytesServerReceived, chunkSize)); 609 request.Content.Headers.Add("Content-Range", GetContentRangeHeader(B ytesServerReceived, chunkSize));
610 610
611 LastMediaLength = chunkSize; 611 LastMediaLength = chunkSize;
612 } 612 }
613 613
614 /// <summary> Returns the next byte index need to be sent. </summary> 614 /// <summary>Returns the next byte index need to be sent.</summary>
615 private long GetNextByte(string range) 615 private long GetNextByte(string range)
616 { 616 {
617 return long.Parse(range.Substring(range.IndexOf('-') 1)) 1; 617 return long.Parse(range.Substring(range.IndexOf('-') 1)) 1;
618 } 618 }
619 619
620 /// <summary> 620 /// <summary>
621 /// Build a content range header of the form: "bytes X-Y/T" where: 621 /// Build a content range header of the form: "bytes X-Y/T" where:
622 /// <list type=""> 622 /// <list type="">
623 /// <item>X is the first byte being sent.</item> 623 /// <item>X is the first byte being sent.</item>
624 /// <item>Y is the last byte in the range being sent (inclusive).</item> 624 /// <item>Y is the last byte in the range being sent (inclusive).</item>
(...skipping 18 matching lines...) Expand all
643 { 643 {
644 return ZeroByteContentRangeHeader; 644 return ZeroByteContentRangeHeader;
645 } 645 }
646 else 646 else
647 { 647 {
648 long chunkEnd = chunkStart chunkSize - 1; 648 long chunkEnd = chunkStart chunkSize - 1;
649 return String.Format("bytes {0}-{1}/{2}", chunkStart, chunkEnd, strLength); 649 return String.Format("bytes {0}-{1}/{2}", chunkStart, chunkEnd, strLength);
650 } 650 }
651 } 651 }
652 652
653 /// <summary> Creates a request to initialize a request. </summary> 653 /// <summary>Creates a request to initialize a request.</summary>
654 private HttpRequestMessage CreateInitializeRequest() 654 private HttpRequestMessage CreateInitializeRequest()
655 { 655 {
656 var builder = new RequestBuilder() 656 var builder = new RequestBuilder()
657 { 657 {
658 BaseUri = new Uri(Service.BaseUri), 658 BaseUri = new Uri(Service.BaseUri),
659 Path = Path, 659 Path = Path,
660 Method = HttpMethod, 660 Method = HttpMethod,
661 }; 661 };
662 662
663 // init parameters 663 // init parameters
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 /// <remarks> 753 /// <remarks>
754 /// This property will be set during upload. The <see cref="ResponseRece ived"/> event 754 /// This property will be set during upload. The <see cref="ResponseRece ived"/> event
755 /// is triggered when this has been set. 755 /// is triggered when this has been set.
756 /// </remarks> 756 /// </remarks>
757 public TResponse ResponseBody { get; private set; } 757 public TResponse ResponseBody { get; private set; }
758 758
759 #endregion // Properties 759 #endregion // Properties
760 760
761 #region Events 761 #region Events
762 762
763 /// <summary> Event which is called when the response metadata is proces sed. </summary> 763 /// <summary>Event which is called when the response metadata is process ed.</summary>
764 public event Action<TResponse> ResponseReceived; 764 public event Action<TResponse> ResponseReceived;
765 765
766 #endregion // Events 766 #endregion // Events
767 767
768 #region Overrides 768 #region Overrides
769 769
770 /// <summary> Process the response body </summary> 770 /// <summary>Process the response body </summary>
771 protected override void ProcessResponse(HttpResponseMessage response) 771 protected override void ProcessResponse(HttpResponseMessage response)
772 { 772 {
773 base.ProcessResponse(response); 773 base.ProcessResponse(response);
774 ResponseBody = Service.DeserializeResponse<TResponse>(response).Resu lt; 774 ResponseBody = Service.DeserializeResponse<TResponse>(response).Resu lt;
775 775
776 if (ResponseReceived != null) 776 if (ResponseReceived != null)
777 ResponseReceived(ResponseBody); 777 ResponseReceived(ResponseBody);
778 } 778 }
779 779
780 #endregion // Overrides 780 #endregion // Overrides
781 } 781 }
782 } 782 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b