Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2019 Google
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSMultipartMimeStreamEncoder.h"
16
 
17
#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"
18
#import "Crashlytics/Shared/FIRCLSByteUtility.h"
19
#import "Crashlytics/Shared/FIRCLSUUID.h"
20
 
21
@interface FIRCLSMultipartMimeStreamEncoder () <NSStreamDelegate>
22
 
23
@property(nonatomic) NSUInteger length;
24
@property(nonatomic, copy) NSString *boundary;
25
@property(nonatomic, copy, readonly) NSData *headerData;
26
@property(nonatomic, copy, readonly) NSData *footerData;
27
@property(nonatomic, strong) NSOutputStream *outputStream;
28
 
29
@end
30
 
31
@implementation FIRCLSMultipartMimeStreamEncoder
32
 
33
+ (void)populateRequest:(NSMutableURLRequest *)request
34
    withDataFromEncoder:(void (^)(FIRCLSMultipartMimeStreamEncoder *encoder))block {
35
  NSString *boundary = [self generateBoundary];
36
 
37
  NSOutputStream *stream = [NSOutputStream outputStreamToMemory];
38
 
39
  FIRCLSMultipartMimeStreamEncoder *encoder =
40
      [[FIRCLSMultipartMimeStreamEncoder alloc] initWithStream:stream andBoundary:boundary];
41
 
42
  [encoder encode:^{
43
    block(encoder);
44
  }];
45
 
46
  [request setValue:encoder.contentTypeHTTPHeaderValue forHTTPHeaderField:@"Content-Type"];
47
  [request setValue:encoder.contentLengthHTTPHeaderValue forHTTPHeaderField:@"Content-Length"];
48
 
49
  NSData *data = [stream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
50
  request.HTTPBody = data;
51
}
52
 
53
+ (NSString *)contentTypeHTTPHeaderValueWithBoundary:(NSString *)boundary {
54
  return [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
55
}
56
 
57
+ (instancetype)encoderWithStream:(NSOutputStream *)stream andBoundary:(NSString *)boundary {
58
  return [[self alloc] initWithStream:stream andBoundary:boundary];
59
}
60
 
61
+ (NSString *)generateBoundary {
62
  return FIRCLSGenerateUUID();
63
}
64
 
65
- (instancetype)initWithStream:(NSOutputStream *)stream andBoundary:(NSString *)boundary {
66
  self = [super init];
67
  if (!self) {
68
    return nil;
69
  }
70
 
71
  self.outputStream = stream;
72
 
73
  if (!boundary) {
74
    boundary = [FIRCLSMultipartMimeStreamEncoder generateBoundary];
75
  }
76
 
77
  _boundary = boundary;
78
 
79
  return self;
80
}
81
 
82
- (void)encode:(void (^)(void))block {
83
  [self beginEncoding];
84
 
85
  block();
86
 
87
  [self endEncoding];
88
}
89
 
90
- (NSString *)contentTypeHTTPHeaderValue {
91
  return [[self class] contentTypeHTTPHeaderValueWithBoundary:self.boundary];
92
}
93
 
94
- (NSString *)contentLengthHTTPHeaderValue {
95
  return [NSString stringWithFormat:@"%lu", (unsigned long)_length];
96
}
97
 
98
#pragma - mark MIME part API
99
- (void)beginEncoding {
100
  _length = 0;
101
 
102
  [self.outputStream open];
103
 
104
  [self writeData:self.headerData];
105
}
106
 
107
- (void)endEncoding {
108
  [self writeData:self.footerData];
109
 
110
  [self.outputStream close];
111
}
112
 
113
- (NSData *)headerData {
114
  return [@"MIME-Version: 1.0\r\n" dataUsingEncoding:NSUTF8StringEncoding];
115
}
116
 
117
- (NSData *)footerData {
118
  return [[NSString stringWithFormat:@"--%@--\r\n", self.boundary]
119
      dataUsingEncoding:NSUTF8StringEncoding];
120
}
121
 
122
- (void)addFileData:(NSData *)data
123
           fileName:(NSString *)fileName
124
           mimeType:(NSString *)mimeType
125
          fieldName:(NSString *)name {
126
  if ([data length] == 0) {
127
    FIRCLSErrorLog(@"Unable to MIME encode data with zero length (%@)", name);
128
    return;
129
  }
130
 
131
  if ([name length] == 0 || [fileName length] == 0) {
132
    FIRCLSErrorLog(@"name (%@) or fieldname (%@) is invalid", name, fileName);
133
    return;
134
  }
135
 
136
  NSMutableString *string;
137
 
138
  string = [NSMutableString
139
      stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",
140
                       self.boundary, name, fileName];
141
 
142
  if (mimeType) {
143
    [string appendFormat:@"Content-Type: %@\r\n", mimeType];
144
    [string appendString:@"Content-Transfer-Encoding: binary\r\n\r\n"];
145
  } else {
146
    [string appendString:@"Content-Type: application/octet-stream\r\n\r\n"];
147
  }
148
 
149
  [self writeData:[string dataUsingEncoding:NSUTF8StringEncoding]];
150
 
151
  [self writeData:data];
152
 
153
  [self writeData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
154
}
155
 
156
- (void)addValue:(id)value fieldName:(NSString *)name {
157
  if ([name length] == 0 || !value || value == NSNull.null) {
158
    FIRCLSErrorLog(@"name (%@) or value (%@) is invalid", name, value);
159
    return;
160
  }
161
 
162
  NSMutableString *string;
163
 
164
  string =
165
      [NSMutableString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n",
166
                                        self.boundary, name];
167
  [string appendString:@"Content-Type: text/plain\r\n\r\n"];
168
  [string appendFormat:@"%@\r\n", value];
169
 
170
  [self writeData:[string dataUsingEncoding:NSUTF8StringEncoding]];
171
}
172
 
173
- (void)addFile:(NSURL *)fileURL
174
       fileName:(NSString *)fileName
175
       mimeType:(NSString *)mimeType
176
      fieldName:(NSString *)name {
177
  NSData *data = [NSData dataWithContentsOfURL:fileURL];
178
 
179
  [self addFileData:data fileName:fileName mimeType:mimeType fieldName:name];
180
}
181
 
182
- (BOOL)writeBytes:(const void *)bytes ofLength:(NSUInteger)length {
183
  if ([self.outputStream write:bytes maxLength:length] != length) {
184
    FIRCLSErrorLog(@"Failed to write bytes to stream");
185
    return NO;
186
  }
187
 
188
  _length += length;
189
 
190
  return YES;
191
}
192
 
193
- (void)writeData:(NSData *)data {
194
  FIRCLSEnumerateByteRangesOfNSDataUsingBlock(
195
      data, ^(const void *bytes, NSRange byteRange, BOOL *stop) {
196
        NSUInteger length = byteRange.length;
197
 
198
        if ([self.outputStream write:bytes maxLength:length] != length) {
199
          FIRCLSErrorLog(@"Failed to write data to stream");
200
          *stop = YES;
201
          return;
202
        }
203
 
204
        self->_length += length;
205
      });
206
}
207
 
208
@end