설명 없음

AWSSerialization.m 68KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704
  1. //
  2. // Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License").
  5. // You may not use this file except in compliance with the License.
  6. // A copy of the License is located at
  7. //
  8. // http://aws.amazon.com/apache2.0
  9. //
  10. // or in the "license" file accompanying this file. This file is distributed
  11. // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  12. // express or implied. See the License for the specific language governing
  13. // permissions and limitations under the License.
  14. //
  15. #import "AWSSerialization.h"
  16. #import "AWSXMLWriter.h"
  17. #import "AWSCategory.h"
  18. #import "AWSCocoaLumberjack.h"
  19. #import "AWSXMLDictionary.h"
  20. NSString *const AWSXMLBuilderErrorDomain = @"com.amazonaws.AWSXMLBuilderErrorDomain";
  21. NSString *const AWSXMLParserErrorDomain = @"com.amazonaws.AWSXMLParserErrorDomain";
  22. NSString *const AWSQueryParamBuilderErrorDomain = @"com.amazonaws.AWSQueryParamBuilderErrorDomain";
  23. NSString *const AWSEC2ParamBuilderErrorDomain = @"com.amazonaws.AWSEC2ParamBuilderErrorDomain";
  24. NSString *const AWSJSONBuilderErrorDomain = @"com.amazonaws.AWSJSONBuilderErrorDomain";
  25. NSString *const AWSJSONParserErrorDomain = @"com.amazonaws.AWSJSONParserErrorDomain";
  26. @interface AWSJSONDictionary()
  27. @property (nonatomic, strong) NSDictionary *embeddedDictionary;
  28. @property (nonatomic, strong) NSDictionary *JSONDefinitionRule;
  29. @end
  30. @implementation AWSJSONDictionary
  31. - (instancetype)initWithDictionary:(NSDictionary *)otherDictionary JSONDefinitionRule:(NSDictionary *)rule {
  32. self = [super init];
  33. if (self) {
  34. _embeddedDictionary = [[NSDictionary alloc] initWithDictionary:otherDictionary];
  35. _JSONDefinitionRule = [rule copy];
  36. }
  37. return self;
  38. }
  39. - (id)parseResult:(id)result {
  40. if ([result isKindOfClass:[NSDictionary class]]) {
  41. return [[AWSJSONDictionary alloc] initWithDictionary:result JSONDefinitionRule:self.JSONDefinitionRule];
  42. } else {
  43. return result;
  44. }
  45. }
  46. - (NSUInteger)count {
  47. return [self.embeddedDictionary count];
  48. }
  49. - (id)objectForKey:(id)aKey {
  50. //If value found, just return value
  51. id value = [self.embeddedDictionary objectForKey:aKey];
  52. if (value) {
  53. return [self parseResult:value];
  54. }
  55. //find value in metadata dictionary, return the value if found
  56. id result = [[self.embeddedDictionary objectForKey:@"metadata"] objectForKey:aKey];
  57. if (result) {
  58. return [self parseResult:result];
  59. }
  60. //find value according to shapeName, return the value if found
  61. NSString *shapeName = [self.embeddedDictionary objectForKey:@"shape"];
  62. if (shapeName.length != 0) {
  63. NSDictionary *definitionResult = [self.JSONDefinitionRule objectForKey:shapeName];
  64. id result = [definitionResult objectForKey:aKey];
  65. if (result) {
  66. return [self parseResult:result];
  67. }
  68. id metaDataResult = [[definitionResult objectForKey:@"metadata"] objectForKey:aKey];
  69. if (metaDataResult) {
  70. return [self parseResult:metaDataResult];
  71. }
  72. }
  73. return nil;
  74. }
  75. - (NSEnumerator *)keyEnumerator {
  76. return [self.embeddedDictionary keyEnumerator];
  77. }
  78. @end
  79. @implementation AWSXMLBuilder
  80. + (BOOL)failWithCode:(NSInteger)code description:(NSString *)description error:(NSError *__autoreleasing *)error {
  81. if (error) {
  82. *error = [NSError errorWithDomain:AWSXMLBuilderErrorDomain
  83. code:code
  84. userInfo:@{NSLocalizedDescriptionKey : description}];
  85. }
  86. return NO;
  87. }
  88. + (NSString *)xmlStringForDictionary:(NSDictionary *)params actionName:(NSString *)actionName serviceDefinitionRule:(NSDictionary *)serviceDefinitionRule error:(NSError *__autoreleasing *)error {
  89. return [[self xmlBuildForDictionary:params actionName:actionName serviceDefinitionRule:serviceDefinitionRule error:error] toString];
  90. }
  91. + (NSData *)xmlDataForDictionary:(NSDictionary *)params actionName:(NSString *)actionName serviceDefinitionRule:(NSDictionary *)serviceDefinitionRule error:(NSError *__autoreleasing *)error {
  92. if ([params count] == 0) {
  93. return nil;
  94. }
  95. NSData *resultData = [[self xmlBuildForDictionary:params actionName:actionName serviceDefinitionRule:serviceDefinitionRule error:error] toData];
  96. return resultData;
  97. }
  98. + (AWSXMLWriter *)xmlBuildForDictionary:(NSDictionary *)params actionName:(NSString *)actionName serviceDefinitionRule:(NSDictionary *)serviceDefinitionRule error:(NSError *__autoreleasing *)error {
  99. NSDictionary *actionRule = [[[serviceDefinitionRule objectForKey:@"operations"] objectForKey:actionName] objectForKey:@"input"];
  100. NSDictionary *definitionRules = [serviceDefinitionRule objectForKey:@"shapes"];
  101. if (definitionRules == (id)[NSNull null] || [definitionRules count] == 0) {
  102. [self failWithCode:AWSXMLBuilderDefinitionFileIsEmpty description:@"JSON definition File is empty or can not be found" error:error];
  103. return nil;
  104. }
  105. if ([actionRule count] == 0) {
  106. [self failWithCode:AWSXMLBuilderUndefinedActionRule description:@"Invalid argument: actionRule is Empty" error:error];
  107. return nil;
  108. }
  109. AWSXMLWriter* xmlWriter = [[AWSXMLWriter alloc]init];
  110. AWSJSONDictionary *rules = [[AWSJSONDictionary alloc] initWithDictionary:actionRule JSONDefinitionRule:definitionRules];
  111. NSString *xmlElementName = rules[@"locationName"];
  112. if (xmlElementName) {
  113. [xmlWriter writeStartElement:xmlElementName];
  114. [self applyNamespacesAndAttributesByRules:rules params:params xmlWriter:xmlWriter];
  115. }
  116. [self serializeStructure:params rules:rules xmlWriter:xmlWriter error:error isRootRule:YES];
  117. if (xmlElementName) {
  118. [xmlWriter writeEndElement:xmlElementName];
  119. }
  120. return xmlWriter;
  121. }
  122. + (BOOL)serializeStructure:(NSDictionary *)params rules:(AWSJSONDictionary *)rules xmlWriter:(AWSXMLWriter *)xmlWriter error:(NSError *__autoreleasing *)error isRootRule:(BOOL)isRootRule {
  123. AWSJSONDictionary *structureMembersRule = rules[@"members"]?rules[@"members"]:@{};
  124. //If it is RootRule, only process payload If it exists.
  125. if (isRootRule) {
  126. NSString *payloadMemberName = rules[@"payload"];
  127. if (payloadMemberName) {
  128. id value = params[payloadMemberName];
  129. if (value) {
  130. AWSJSONDictionary *payloadMemberRules = structureMembersRule[payloadMemberName];
  131. return [self serializeMember:value name:payloadMemberName rules:payloadMemberRules isPayloadType:YES xmlWriter:xmlWriter error:error];
  132. } else {
  133. //no payload exists, should return
  134. return YES;
  135. }
  136. }
  137. //if no payload trait, continue to process
  138. }
  139. __block BOOL isValid = YES;
  140. __block NSError *blockErr = nil;
  141. [structureMembersRule enumerateKeysAndObjectsUsingBlock:^(NSString *memberName, id memberRules, BOOL *stop) {
  142. id value = params[memberName];
  143. if (value) {
  144. if (memberRules[@"xmlAttribute"]) {
  145. //It should be an attribute, will be proceed in applyNamespacesAndAttributesByRules
  146. return;
  147. }
  148. if (memberRules[@"location"]) {
  149. //It should be another location rather than body, will be process at different place
  150. return;
  151. }
  152. if (![self serializeMember:value name:memberName rules:memberRules isPayloadType:NO xmlWriter:xmlWriter error:&blockErr]) {
  153. *stop = YES;
  154. isValid = NO;
  155. return;
  156. }
  157. }
  158. }];
  159. if (error) *error = blockErr;
  160. return isValid;
  161. }
  162. + (BOOL)serializeList:(NSArray *)list name:(NSString *)name rules:(AWSJSONDictionary *)rules xmlWriter:(AWSXMLWriter *)xmlWriter error:(NSError *__autoreleasing *)error {
  163. AWSJSONDictionary *memberRules = rules[@"member"]?rules[@"member"]:@{};
  164. NSString *xmlListName = rules[@"locationName"]?rules[@"locationName"]:name;
  165. __block BOOL isValid = YES;
  166. __block NSError *blockErr = nil;
  167. if ([rules[@"flattened"] boolValue]) {
  168. [list enumerateObjectsUsingBlock:^(id value, NSUInteger idx, BOOL *stop) {
  169. if (![self serializeMember:value name:xmlListName rules:memberRules isPayloadType:NO xmlWriter:xmlWriter error:&blockErr]) {
  170. *stop = YES;
  171. isValid = NO;
  172. return ;
  173. }
  174. }];
  175. } else {
  176. //Add a extra layer for non-flattened format.
  177. [xmlWriter writeStartElement:xmlListName];
  178. [list enumerateObjectsUsingBlock:^(id value, NSUInteger idx, BOOL *stop) {
  179. //non-flattened list without locationName should use 'member' as default name
  180. if (![self serializeMember:value name:@"member" rules:memberRules isPayloadType:NO xmlWriter:xmlWriter error:&blockErr]) {
  181. *stop = YES;
  182. isValid = NO;
  183. return ;
  184. }
  185. }];
  186. [xmlWriter writeEndElement:xmlListName];
  187. }
  188. if (error) *error = blockErr;
  189. return isValid;
  190. }
  191. + (BOOL)serializeMember:(id)params name:(NSString *)memberName rules:(AWSJSONDictionary *)rules isPayloadType:(Boolean)isPayloadType xmlWriter:(AWSXMLWriter *)xmlWriter error:(NSError *__autoreleasing *)error {
  192. NSString *xmlElementName = rules[@"locationName"]?rules[@"locationName"]:memberName;
  193. NSString *rulesType = rules[@"type"];
  194. if ([rulesType isEqualToString:@"structure"]) {
  195. [xmlWriter writeStartElement:xmlElementName];
  196. [self applyNamespacesAndAttributesByRules:rules params:params xmlWriter:xmlWriter];
  197. [self serializeStructure:params rules:rules xmlWriter:xmlWriter error:error isRootRule:NO];
  198. [xmlWriter writeEndElement:xmlElementName];
  199. } else if ([rulesType isEqualToString:@"list"]) {
  200. [self serializeList:params name:memberName rules:rules xmlWriter:xmlWriter error:error];
  201. } else if ([rulesType isEqualToString:@"map"]) {
  202. //TODO: handle map type
  203. } else if ([rulesType isEqualToString:@"timestamp"]) {
  204. NSDate *timeStampDate;
  205. //maybe a NSDate type or NSNumber type or NSString type
  206. if ([params isKindOfClass:[NSString class]]) {
  207. //try parse the string to NSDate first
  208. timeStampDate = [NSDate aws_dateFromString:params];
  209. //if failed, then parse it as double value
  210. if (!timeStampDate) {
  211. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[params doubleValue]];
  212. }
  213. } else if ([params isKindOfClass:[NSNumber class]]) {
  214. //need to convert to NSDate type
  215. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[params doubleValue]];
  216. } else if ([params isKindOfClass:[NSDate class]]) {
  217. timeStampDate = params;
  218. }
  219. //generate string presentation of timestamp
  220. NSString *timestampStr = @"";
  221. if ([rules[@"timestampFormat"] isEqualToString:@"iso8601"]) {
  222. timestampStr = [timeStampDate aws_stringValue:AWSDateISO8601DateFormat1];
  223. } else if ([rules[@"timestampFormat"] isEqualToString:@"unixTimestamp"]) {
  224. timestampStr = [NSString stringWithFormat:@"%.lf",[timeStampDate timeIntervalSince1970]];
  225. } else {
  226. timestampStr = [timeStampDate aws_stringValue:AWSDateRFC822DateFormat1];
  227. }
  228. if (isPayloadType == NO) [xmlWriter writeStartElement:xmlElementName];
  229. [xmlWriter writeCharacters:timestampStr];
  230. if (isPayloadType == NO) [xmlWriter writeEndElement:xmlElementName];
  231. } else if ([rulesType isEqualToString:@"integer"] || [rulesType isEqualToString:@"long"] || [rulesType isEqualToString:@"float"] || [rulesType isEqualToString:@"double"]) {
  232. NSNumber *numberValue = params;
  233. if (isPayloadType == NO) [xmlWriter writeStartElement:xmlElementName];
  234. [xmlWriter writeCharacters:[numberValue stringValue]];
  235. if (isPayloadType == NO) [xmlWriter writeEndElement:xmlElementName];
  236. } else if ([rulesType isEqualToString:@"blob"]) {
  237. //just handle the non-streaming body, streaming body will be handled in 'constructURIandHeadersAndBody' method
  238. if ([rules[@"streaming"] boolValue] == NO) {
  239. //encode NSData to Base64String
  240. if ([params isKindOfClass:[NSString class]]) {
  241. params = [params dataUsingEncoding:NSUTF8StringEncoding];
  242. }
  243. if ([params isKindOfClass:[NSData class]]) {
  244. if (isPayloadType == NO) {
  245. NSString *base64encodedStr = [params base64EncodedStringWithOptions:0];
  246. [xmlWriter writeStartElement:xmlElementName];
  247. [xmlWriter writeCharacters:base64encodedStr];
  248. [xmlWriter writeEndElement:xmlElementName];
  249. } else {
  250. //Do not base64 encoding if it is payload type
  251. NSString* utf8String = [[NSString alloc] initWithData:params encoding:NSUTF8StringEncoding];
  252. [xmlWriter writeCharacters:utf8String?utf8String:@""];
  253. }
  254. } else {
  255. [self failWithCode:AWSXMLBuilderInvalidXMLValue description:@"'blob' value should be a NSData type." error:error];
  256. return NO;
  257. }
  258. }
  259. } else if ([rulesType isEqualToString:@"boolean"]) {
  260. if (isPayloadType == NO) [xmlWriter writeStartElement:xmlElementName];
  261. [xmlWriter writeCharacters:[params boolValue]?@"true":@"false"];
  262. if (isPayloadType == NO) [xmlWriter writeEndElement:xmlElementName];
  263. } else if ([rulesType isEqualToString:@"string"]) {
  264. if (isPayloadType == NO) [xmlWriter writeStartElement:xmlElementName];
  265. [xmlWriter writeCharacters:params];
  266. if (isPayloadType == NO) [xmlWriter writeEndElement:xmlElementName];
  267. } else {
  268. [self failWithCode:AWSXMLBuilderUnCatchedRuleTypeInDifinitionFile description:[NSString stringWithFormat:@"uncatched ruletype:%@ for value:%@",rulesType,[params description]] error:error];
  269. return NO;
  270. }
  271. return YES;
  272. }
  273. + (void)applyNamespacesAndAttributesByRules:(NSDictionary *)rules params:(id)params xmlWriter:(AWSXMLWriter *)xmlWriter {
  274. id xmlNamespaceValue = rules[@"xmlNamespace"];
  275. if (xmlNamespaceValue) {
  276. if ([xmlNamespaceValue isKindOfClass:[NSDictionary class]]) {
  277. NSString *xmlnsName = @"xmlns";
  278. if (xmlNamespaceValue[@"prefix"]) {
  279. xmlnsName = [xmlnsName stringByAppendingString:[NSString stringWithFormat:@":%@",xmlNamespaceValue[@"prefix"]]];
  280. }
  281. [xmlWriter writeAttribute:xmlnsName value:xmlNamespaceValue[@"uri"]];
  282. } else if ([xmlNamespaceValue isKindOfClass:[NSString class]]) {
  283. NSString *xmlnsName = @"xmlns";
  284. [xmlWriter writeAttribute:xmlnsName value:xmlNamespaceValue];
  285. }
  286. }
  287. if ([rules[@"members"][@"Type"][@"xmlAttribute"] boolValue]) {
  288. NSString *xmlName = rules[@"members"][@"Type"][@"locationName"];
  289. if (params[@"Type"]) {
  290. [xmlWriter writeAttribute:xmlName value:params[@"Type"]];
  291. }
  292. }
  293. }
  294. @end
  295. @interface AWSXMLParser ()
  296. @property (nonatomic, strong) AWSXMLDictionaryParser *xmlDictionaryParser;
  297. @end
  298. @implementation AWSXMLParser
  299. + (AWSXMLParser *)sharedInstance {
  300. static dispatch_once_t once;
  301. static AWSXMLParser *sharedInstance;
  302. dispatch_once(&once, ^{
  303. sharedInstance = [AWSXMLParser new];
  304. });
  305. return sharedInstance;
  306. }
  307. - (instancetype)init {
  308. if (self = [super init]) {
  309. _xmlDictionaryParser = [AWSXMLDictionaryParser new];
  310. _xmlDictionaryParser.trimWhiteSpace = NO;
  311. _xmlDictionaryParser.attributesMode = AWSXMLDictionaryAttributesModeDiscard; //discard all xml attributes. e.g. xmlns
  312. _xmlDictionaryParser.stripEmptyNodes = NO;
  313. _xmlDictionaryParser.wrapRootNode = YES; //wrapRootNode for easy process
  314. _xmlDictionaryParser.nodeNameMode = AWSXMLDictionaryNodeNameModeNever; //do not need rootName anymore since rootNode is wrapped.
  315. }
  316. return self;
  317. }
  318. + (BOOL)failWithCode:(NSInteger)code description:(NSString *)description error:(NSError *__autoreleasing *)error {
  319. if (error) {
  320. *error = [NSError errorWithDomain:AWSXMLParserErrorDomain
  321. code:code
  322. userInfo:@{NSLocalizedDescriptionKey : description}];
  323. }
  324. return NO;
  325. }
  326. + (NSMutableDictionary *)preprocessDictionary:(NSMutableDictionary *)fromDictionary operationName:(NSString *)operationName actionRule:(NSDictionary *)actionRule serviceDefinitionRule:(NSDictionary *)serviceDefinitionRule {
  327. NSString *serviceTypeStr = serviceDefinitionRule[@"metadata"][@"type"]?serviceDefinitionRule[@"metadata"][@"type"]:serviceDefinitionRule[@"metadata"][@"protocol"];
  328. if ([serviceTypeStr isEqualToString:@"query"]) {
  329. NSNumber *isResultWrapped = serviceDefinitionRule[@"metadata"][@"resultWrapped"];
  330. if (isResultWrapped && ![isResultWrapped boolValue]) {
  331. //If resultWrapped is false
  332. return fromDictionary;
  333. } else {
  334. //If not set, it is true by default
  335. if (actionRule[@"resultWrapper"] && fromDictionary[actionRule[@"resultWrapper"]]) {
  336. return fromDictionary[actionRule[@"resultWrapper"]];
  337. } else if ([operationName stringByAppendingString:@"Result"] && fromDictionary[[operationName stringByAppendingString:@"Result"]]){
  338. return fromDictionary[[operationName stringByAppendingString:@"Result"]];
  339. } else {
  340. return fromDictionary;
  341. }
  342. }
  343. } else if ([serviceTypeStr isEqualToString:@"rest-xml"]) {
  344. //TODO: handle rest-xml type for Route 53 and S3
  345. return fromDictionary;
  346. } else if ([serviceTypeStr isEqualToString:@"json"]) {
  347. return fromDictionary;
  348. } else if ([serviceTypeStr isEqualToString:@"rest-json"]) {
  349. return fromDictionary;
  350. } else {
  351. return fromDictionary;
  352. }
  353. }
  354. - (NSMutableDictionary *)dictionaryForXMLData:(NSData *)data
  355. actionName:(NSString *)actionName
  356. serviceDefinitionRule:(NSDictionary *)serviceDefinitionRule
  357. error:(NSError *__autoreleasing *)error {
  358. if (!data) {
  359. return [NSMutableDictionary new];
  360. }
  361. NSDictionary *actionRule = [[[serviceDefinitionRule objectForKey:@"operations"] objectForKey:actionName] objectForKey:@"output"];
  362. if (actionRule == (id)[NSNull null]) {
  363. actionRule = @{};
  364. }
  365. NSDictionary *definitionRules = [serviceDefinitionRule objectForKey:@"shapes"];
  366. if (definitionRules == (id)[NSNull null]) {
  367. definitionRules = @{};
  368. }
  369. if ([definitionRules count] == 0) {
  370. if (error) {
  371. *error = [NSError errorWithDomain:AWSXMLParserErrorDomain
  372. code:AWSXMLParserDefinitionFileIsEmpty
  373. userInfo:@{
  374. NSLocalizedDescriptionKey : @"JSON definition File is empty or can not be found"
  375. }];
  376. }
  377. return nil;
  378. }
  379. NSMutableDictionary *rootXmlDictionary = nil;
  380. if ([data isKindOfClass:[NSData class]]) {
  381. @synchronized (self) {
  382. rootXmlDictionary = [[self.xmlDictionaryParser dictionaryWithData:data] mutableCopy]; //TODO: need error parameters for parsing
  383. }
  384. }
  385. NSString *rootNodeName = [[rootXmlDictionary allKeys] firstObject];
  386. NSMutableDictionary *xmlDictionary = ([rootXmlDictionary[rootNodeName] isKindOfClass:[NSDictionary class]] && [rootXmlDictionary[rootNodeName] count] > 0)?rootXmlDictionary[rootNodeName]:rootXmlDictionary;
  387. if (*error) {
  388. return nil;
  389. } else if ([rootNodeName isEqualToString:@"Error"]) {
  390. //This is an S3 error response, just return parsed xmlDictionary.
  391. return [@{rootNodeName:xmlDictionary} mutableCopy];
  392. } else if ([xmlDictionary objectForKey:@"Errors"]) {
  393. //This is EC2 error response.
  394. if ([[xmlDictionary objectForKey:@"Errors"] isKindOfClass:[NSDictionary class]]) {
  395. return [xmlDictionary objectForKey:@"Errors"];
  396. } else if ([[xmlDictionary objectForKey:@"Errors"] isKindOfClass:[NSArray class]]) {
  397. return [[xmlDictionary objectForKey:@"Errors"] firstObject];
  398. }
  399. return nil;
  400. }else if ([xmlDictionary objectForKey:@"Error"]) {
  401. //This is mostly used error response, return xmlDictionary
  402. return [xmlDictionary mutableCopy];
  403. }else {
  404. AWSJSONDictionary *rules = [[AWSJSONDictionary alloc] initWithDictionary:actionRule JSONDefinitionRule:definitionRules];
  405. xmlDictionary = [AWSXMLParser preprocessDictionary:xmlDictionary operationName:actionName actionRule:rules serviceDefinitionRule:serviceDefinitionRule];
  406. NSString *isPayloadData = rules[@"payload"];
  407. rules = rules[@"members"]?rules[@"members"]:@{};
  408. NSMutableDictionary *parsedData = [NSMutableDictionary new];
  409. if (isPayloadData) {
  410. //check if it is streaming type
  411. if (rules[isPayloadData][@"streaming"]) {
  412. parsedData[isPayloadData] = data;
  413. return parsedData;
  414. }
  415. rules = rules[isPayloadData][@"members"];
  416. parsedData[isPayloadData] = [AWSXMLParser parseStructure:xmlDictionary rules:rules error:error];
  417. } else {
  418. parsedData = [AWSXMLParser parseStructure:xmlDictionary rules:rules error:error];
  419. }
  420. if ([parsedData count] == 0) {
  421. //try again with rootDictionary if it is S3 response
  422. NSString *serviceTypeStr = serviceDefinitionRule[@"metadata"][@"type"]?serviceDefinitionRule[@"metadata"][@"type"]:serviceDefinitionRule[@"metadata"][@"protocol"];
  423. if ([serviceTypeStr isEqualToString:@"rest-xml"]) {
  424. xmlDictionary = [AWSXMLParser preprocessDictionary:xmlDictionary operationName:actionName actionRule:actionRule serviceDefinitionRule:serviceDefinitionRule];
  425. parsedData = [AWSXMLParser parseStructure:xmlDictionary rules:rules error:error];
  426. }
  427. }
  428. return parsedData;
  429. };
  430. }
  431. + (NSString *)findKeyNameByXMLName:(NSString *)xmlName rules:(NSDictionary *)rules {
  432. __block NSString *result;
  433. [rules enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
  434. if ([key isEqualToString:xmlName]) {
  435. result = key;
  436. *stop = YES;
  437. return;
  438. }
  439. if ([obj isKindOfClass:[NSDictionary class]] && ([obj[@"type"] isEqualToString:@"list"] || [obj[@"type"] isEqualToString:@"map"])) {
  440. if ([obj[@"flattened"] boolValue]) {
  441. NSString *objXMLName = obj[@"member"][@"locationName"]?obj[@"member"][@"locationName"]:obj[@"locationName"];
  442. objXMLName = objXMLName?objXMLName:@"member";
  443. if ([xmlName isEqualToString:objXMLName]) {
  444. result = key;
  445. *stop = YES;
  446. return;
  447. }
  448. } else {
  449. if ([xmlName isEqualToString:obj[@"locationName"]]) {
  450. result = key;
  451. *stop = YES;
  452. return;
  453. }
  454. }
  455. }
  456. if ([obj isKindOfClass:[NSDictionary class]] && [obj objectForKey:@"locationName"]) {
  457. if ([xmlName isEqualToString:[obj objectForKey:@"locationName"]]) {
  458. result = key;
  459. *stop = YES;
  460. return;
  461. }
  462. }
  463. }];
  464. return result;
  465. }
  466. + (BOOL)validateConstraint:(id)value rules:(NSDictionary *)rules error:(NSError *__autoreleasing *)error {
  467. // //validate the existence of required parameters.
  468. // while ([rules[@"required"] boolValue]) {
  469. // //value is a structure or map
  470. // if ([value isKindOfClass:[NSDictionary class]] && [value count]>0) break;
  471. // //value is a list
  472. // if ([value isKindOfClass:[NSArray class]] && [value count]>0) break;
  473. // //value is a string
  474. // if ([value isKindOfClass:[NSString class]] && [value length] > 0) break;
  475. // //value is NSNumber( e.g long, integer, double, float)
  476. // if ([value isKindOfClass:[NSNumber class]]) break;
  477. //
  478. // return [self failWithCode:AWSXMLParserMissingRequiredXMLElements
  479. // description:[NSString stringWithFormat:@"Missing required key."]
  480. // error:error];
  481. // }
  482. //
  483. // //validate value of string according to enum list
  484. // if (rules[@"enum"] && [value isKindOfClass:[NSString class]]) {
  485. // NSArray *enumArray = rules[@"enum"];
  486. // if (![enumArray containsObject:value]) {
  487. // return [self failWithCode:AWSXMLParserInvalidXMLValue
  488. // description:[NSString stringWithFormat:@"got unexpected string:%@ not in the enum list:%@", value, [enumArray description]]
  489. // error:error];
  490. // }
  491. // }
  492. return YES;
  493. }
  494. + (NSMutableDictionary *)parseStructure:(NSDictionary *)structure rules:(AWSJSONDictionary *)rules error:(NSError *__autoreleasing *)error {
  495. NSMutableDictionary *data = [NSMutableDictionary dictionary];
  496. if (![self validateConstraint:structure rules:rules error:error]) {
  497. return data;
  498. }
  499. __block NSError *blockErr = nil;
  500. [structure enumerateKeysAndObjectsUsingBlock:^(NSString *xmlName, id value, BOOL *stop) {
  501. if ([xmlName isEqualToString:@"$"]) {
  502. } else {
  503. NSString *keyName = [self findKeyNameByXMLName:xmlName rules:rules];
  504. if (!keyName) {
  505. if (![xmlName isEqualToString:@"_xmlns"] &&
  506. ![xmlName isEqualToString:@"requestId"] &&
  507. ![xmlName isEqualToString:@"ResponseMetadata"] &&
  508. ![xmlName isEqualToString:@"__text"]) {
  509. AWSDDLogWarn(@"Response element ignored: no rule for %@ - %@", xmlName, [value description]);
  510. }
  511. /*[self failWithCode:AWSXMLParserXMLNameNotFoundInDefinition
  512. description:[NSString stringWithFormat:@"Can not find the xmlName:%@ in definition to validate xml data", xmlName]
  513. error:&blockErr];
  514. *stop = YES;
  515. */
  516. return;
  517. }
  518. AWSJSONDictionary *rule = rules[keyName];
  519. if ([rules count] == 0) {
  520. [self failWithCode:AWSXMLParserUnexpectedXMLElement description:[NSString stringWithFormat:@"Unexpected XML Element found:%@",xmlName] error:&blockErr];
  521. *stop = YES;
  522. } else {
  523. NSString *dicName = rule[@"name"]?rule[@"name"]:keyName;
  524. data[dicName] = [self parseMember:value rules:rule error:&blockErr];
  525. if (blockErr) *stop = YES;
  526. }
  527. }
  528. }];
  529. if (error) *error = blockErr;
  530. return data;
  531. }
  532. + (NSMutableDictionary *)parseMap:(id)map rules:(AWSJSONDictionary *)rules error:(NSError *__autoreleasing *)error {
  533. AWSJSONDictionary *keyRules = rules[@"key"]?rules[@"key"]:@{};
  534. AWSJSONDictionary *valueRules = rules[@"value"]?rules[@"value"]:@{};
  535. NSString *keyName = keyRules[@"locationName"]?keyRules[@"locationName"]:@"key";
  536. NSString *valueName = valueRules[@"locationName"]?valueRules[@"locationName"]:@"value";
  537. __block NSMutableDictionary *data = [NSMutableDictionary dictionary];
  538. if (![self validateConstraint:map rules:rules error:error]) return data;
  539. NSArray *mapList = nil;
  540. if ([rules[@"flattened"] boolValue] == NO) {
  541. //If it is non-flatened map,retrive the array with key 'entry' if it has one
  542. if ([map isKindOfClass:[NSDictionary class]] && [map objectForKey:@"entry"]) {
  543. mapList = [map objectForKey:@"entry"];
  544. } else {
  545. mapList = map;
  546. }
  547. } else {
  548. mapList = map;
  549. }
  550. //if no content, return empty dictionary
  551. if (!mapList) {
  552. return data;
  553. }
  554. // if 'map' array has only one entry, it will be treat as dictionary, we need to add a array wrapper for that.
  555. if ([mapList isKindOfClass:[NSDictionary class]]) {
  556. mapList = @[mapList];
  557. }
  558. if (![mapList isKindOfClass:[NSArray class]]) {
  559. [self failWithCode:AWSXMLParserUnExpectedType description:[NSString stringWithFormat:@"xml(mapList type) should be an array but got:%@",NSStringFromClass([mapList class])] error:error];
  560. return [NSMutableDictionary new];
  561. } else {
  562. __block NSError *blockErr = nil;
  563. [mapList enumerateObjectsUsingBlock:^(id entry, NSUInteger idx, BOOL *stop) {
  564. NSString *dataKeyName = entry[keyName];
  565. if (dataKeyName) {
  566. data[dataKeyName] = [self parseMember:entry[valueName] rules:valueRules error:&blockErr];
  567. if (blockErr) *stop = YES;
  568. }
  569. }];
  570. if (error) *error = blockErr;
  571. return data;
  572. }
  573. }
  574. + (NSArray *)parseList:(id)list rules:(AWSJSONDictionary *)rules error:(NSError *__autoreleasing *)error {
  575. AWSJSONDictionary *memberRules = rules[@"member"]?rules[@"member"]:@{};
  576. __block NSMutableArray *data = [NSMutableArray array];
  577. if (![self validateConstraint:list rules:rules error:error]) return data;
  578. __block NSError *blockErr = nil;
  579. //If not flattened, need to manually flatten it.
  580. if (![rules[@"flattened"] boolValue]) {
  581. NSString *memberName = memberRules[@"locationName"]?memberRules[@"locationName"]:@"member";
  582. if (![list isKindOfClass:[NSDictionary class]]) {
  583. [self failWithCode:AWSXMLParserUnExpectedType description:[NSString stringWithFormat:@"unflattened xml(list type) should be dictionary but got:%@",NSStringFromClass([list class])] error:error];
  584. return @[];
  585. }
  586. if ([list count] == 0) {
  587. return @[];
  588. }
  589. list = list[memberName];
  590. if (!list) {
  591. [self failWithCode:AWSXMLParserUnExpectedType description:[NSString stringWithFormat:@"Can not find the '%@' key-pair in un-falttened xml list type",memberName] error:error];
  592. return @[@"XMLPARSER:ERROR"];
  593. }
  594. }
  595. if ([list isKindOfClass:[NSDictionary class]]) {
  596. // if 'list' isn't an array but a dictionary, we create a new array containing our object.
  597. list = @[list];
  598. }
  599. if (![list isKindOfClass:[NSArray class]]) {
  600. return @[list];
  601. }
  602. [list enumerateObjectsUsingBlock:^(id value, NSUInteger idx, BOOL *stop) {
  603. [data addObject:[self parseMember:value rules:memberRules error:&blockErr]];
  604. if (blockErr) *stop = YES;
  605. }];
  606. if (error) *error = blockErr;
  607. return data;
  608. }
  609. + (id)parseMember:(id)values rules:(AWSJSONDictionary *)rules error:(NSError *__autoreleasing *)error {
  610. NSString *rulesType = rules[@"type"];
  611. //if value is nil, return error or empty array/dictionary.
  612. if (!values) {
  613. if ([rulesType isEqualToString:@"structure"]) return @{};
  614. if ([rulesType isEqualToString:@"list"]) return @[];
  615. if ([rulesType isEqualToString:@"map"]) return @{};
  616. return @"XMLPARSER:ERROR";
  617. }
  618. //if there is no 'type' key in rules, return nil with error
  619. if (!rulesType) {
  620. [self failWithCode:AWSXMLParserNoTypeDefinitionInRule description:[NSString stringWithFormat:@"can not find the 'type' keywords in definition file:%@ for value:%@",[rules description],[values description]] error:error];
  621. return @"XMLPARSER:ERROR";
  622. }
  623. //validate the value
  624. if (![self validateConstraint:values rules:rules error:error]) return @"XMLPARSER:ERROR";
  625. if ([rulesType isEqualToString:@"string"] || [rulesType isEqualToString:@"character"]) {
  626. if ([values isKindOfClass:[NSString class]]) {
  627. return values;
  628. } else if ([values isKindOfClass:[NSDictionary class]] && [values count] == 0) {
  629. return @"";
  630. } else {
  631. return [values description];
  632. }
  633. } else if ([rulesType isEqualToString:@"structure"]) {
  634. return [self parseStructure:values rules:rules[@"members"]?rules[@"members"]:@{} error:error];
  635. } else if ([rulesType isEqualToString:@"list"]) {
  636. return [self parseList:values rules:rules error:error];
  637. } else if ([rulesType isEqualToString:@"map"]) {
  638. return [self parseMap:values rules:rules error:error];
  639. } else if ([rulesType isEqualToString:@"integer"] || [rulesType isEqualToString:@"long"]) {
  640. if ([values isKindOfClass:[NSNumber class]]) {
  641. return values;
  642. } else if ([values isKindOfClass:[NSString class]]) {
  643. return [NSNumber numberWithInteger:[values integerValue]];
  644. }
  645. } else if ([rulesType isEqualToString:@"float"] || [rulesType isEqualToString:@"double"]) {
  646. if ([values isKindOfClass:[NSNumber class]]) {
  647. return values;
  648. } else if ([values isKindOfClass:[NSString class]]) {
  649. return [NSNumber numberWithDouble:[values doubleValue]];
  650. }
  651. } else if ([rulesType isEqualToString:@"boolean"]) {
  652. if ([values isKindOfClass:[NSNumber class]]) {
  653. return values;
  654. } else if ([values isKindOfClass:[NSString class]]) {
  655. return [NSNumber numberWithBool:[values boolValue]];
  656. }
  657. } else if ([rulesType isEqualToString:@"timestamp"]) {
  658. //a value with NSNumber type should be a good timestamp.
  659. NSDate *timeStampDate;
  660. //maybe a NSDate type or NSNumber type or NSString type
  661. if ([values isKindOfClass:[NSString class]]) {
  662. //try parse the string to NSDate first
  663. timeStampDate = [NSDate aws_dateFromString:values];
  664. //if failed, then parse it as double value
  665. if (!timeStampDate) {
  666. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[values doubleValue]];
  667. }
  668. } else if ([values isKindOfClass:[NSNumber class]]) {
  669. //need to convert to NSDate type
  670. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[values doubleValue]];
  671. } else if ([values isKindOfClass:[NSDate class]]) {
  672. timeStampDate = values;
  673. }
  674. //generate string presentation of timestamp
  675. NSString *timestampStr = @"";
  676. if ([rules[@"timestampFormat"] isEqualToString:@"iso8601"]) {
  677. timestampStr = [timeStampDate aws_stringValue:AWSDateISO8601DateFormat1];
  678. } else if ([rules[@"timestampFormat"] isEqualToString:@"unixTimestamp"]) {
  679. timestampStr = [NSString stringWithFormat:@"%.lf",[timeStampDate timeIntervalSince1970]];
  680. } else {
  681. timestampStr = [timeStampDate aws_stringValue:AWSDateISO8601DateFormat1];
  682. }
  683. return timestampStr;
  684. } else if ([rulesType isEqualToString:@"blob"]) {
  685. //decode Base64Str to NSData
  686. if ([values isKindOfClass:[NSString class]]) {
  687. NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:values options:0];
  688. //return origin string value if can not be encoded.
  689. return decodedData?decodedData:values;
  690. } else {
  691. [self failWithCode:AWSXMLParserInvalidXMLValue description:@"blob value should be NSString type" error:error];
  692. return [NSData new];
  693. }
  694. }
  695. [self failWithCode:AWSXMLParserUnHandledType description:[NSString stringWithFormat:@"unhandled type for value:%@",[values description]] error:error];
  696. return @"XMLPARSER:ERROR";
  697. }
  698. @end
  699. @implementation AWSQueryParamBuilder
  700. + (BOOL)failWithCode:(NSInteger)code description:(NSString *)description error:(NSError *__autoreleasing *)error {
  701. if (error) {
  702. *error = [NSError errorWithDomain:AWSQueryParamBuilderErrorDomain
  703. code:code
  704. userInfo:@{NSLocalizedDescriptionKey : description}];
  705. }
  706. return NO;
  707. }
  708. + (NSDictionary *)buildFormattedParams:(NSDictionary *)params
  709. actionName:(NSString *)actionName
  710. serviceDefinitionRule:(NSDictionary *)serviceDefinitionRule
  711. error:(NSError *__autoreleasing *)error {
  712. NSMutableDictionary *formattedParams = [NSMutableDictionary new];
  713. //add ActionName
  714. NSString *urlEncodedActionName = [actionName aws_stringWithURLEncoding];
  715. if (!urlEncodedActionName) {
  716. AWSDDLogError(@"actionName is nil!");
  717. [self failWithCode:AWSQueryParamBuilderUndefinedActionRule description:@"actionName is nil" error:error];
  718. return nil;
  719. }
  720. [formattedParams setObject:urlEncodedActionName forKey:@"Action"];
  721. //add Version Number
  722. if (serviceDefinitionRule[@"metadata"] && serviceDefinitionRule[@"metadata"][@"apiVersion"] && [serviceDefinitionRule[@"metadata"][@"apiVersion"] isKindOfClass:[NSString class]]) {
  723. NSString *urlEncodedAPIVersion = [serviceDefinitionRule[@"metadata"][@"apiVersion"] aws_stringWithURLEncoding];
  724. if (urlEncodedAPIVersion) {
  725. [formattedParams setObject:urlEncodedAPIVersion forKey:@"Version"];
  726. } else {
  727. AWSDDLogError(@"can not encode APIVersion String:%@",urlEncodedAPIVersion);
  728. }
  729. } else {
  730. AWSDDLogError(@"can not find apiVersion keyword in definition file!");
  731. }
  732. if ([params count] == 0) {
  733. return formattedParams;
  734. }
  735. //add params
  736. NSDictionary *actionRule = [[[serviceDefinitionRule objectForKey:@"operations"] objectForKey:actionName] objectForKey:@"input"];
  737. NSDictionary *definitionRules = [serviceDefinitionRule objectForKey:@"shapes"];
  738. if (definitionRules == (id)[NSNull null] || [definitionRules count] == 0) {
  739. [self failWithCode:AWSQueryParamBuilderDefinitionFileIsEmpty description:@"JSON definition File is empty or can not be found" error:error];
  740. return nil;
  741. }
  742. if ([actionRule count] == 0) {
  743. [self failWithCode:AWSQueryParamBuilderUndefinedActionRule description:@"Invalid argument: actionRule is Empty" error:error];
  744. return nil;
  745. }
  746. AWSJSONDictionary *rules = [[AWSJSONDictionary alloc] initWithDictionary:actionRule JSONDefinitionRule:definitionRules];
  747. [AWSQueryParamBuilder serializeStructure:params rules:rules prefix:@"" formattedParams:formattedParams error:error];
  748. return formattedParams;
  749. }
  750. + (BOOL)serializeStructure:(NSDictionary *)values rules:(AWSJSONDictionary *)structureRules prefix:(NSString *)prefix formattedParams:(NSMutableDictionary *)formattedParams error:(NSError *__autoreleasing *)error {
  751. for (NSString *name in values) {
  752. id value = values[name];
  753. AWSJSONDictionary *memberShape = structureRules[@"members"][name];
  754. if (memberShape && value) {
  755. [self serializeMember:value rules:memberShape prefix:[NSString stringWithFormat:@"%@%@",prefix,[self queryName:memberShape withDefaultName:name]] formattedParams:formattedParams error:error];
  756. if (error && *error != nil) {
  757. return NO;
  758. }
  759. }
  760. }
  761. return YES;
  762. }
  763. + (BOOL)serializeList:(NSArray *)values rules:(AWSJSONDictionary *)listRules prefix:(NSString *)prefix formattedParams:(NSMutableDictionary *)formattedParams error:(NSError *__autoreleasing *)error {
  764. if (values == nil) {
  765. if (prefix) {
  766. [formattedParams setObject:prefix forKey:@""];
  767. }
  768. return YES;
  769. }
  770. if ([listRules[@"flattened"] boolValue]) {
  771. NSString *memberName = [self queryName:listRules[@"member"] withDefaultName:nil];
  772. if (memberName) {
  773. //substitute memberName
  774. NSMutableArray *parts = [[prefix componentsSeparatedByString:@"."] mutableCopy];
  775. if (parts) {
  776. [parts removeLastObject];
  777. [parts addObject:memberName];
  778. prefix = [[parts componentsJoinedByString:@"."] mutableCopy];
  779. }
  780. }
  781. } else {
  782. prefix = [prefix stringByAppendingString:@".member"];
  783. }
  784. for (int i = 0; i < [values count]; i++) {
  785. id value = values[i];
  786. [self serializeMember:value rules:listRules[@"member"] prefix:[NSString stringWithFormat:@"%@.%d",prefix,i+1] formattedParams:formattedParams error:error];
  787. if (error && *error != nil) {
  788. return NO;
  789. }
  790. }
  791. return YES;
  792. }
  793. + (BOOL)serializeMap:(NSDictionary *)values rules:(AWSJSONDictionary *)mapRules prefix:(NSString *)prefix formattedParams:(NSMutableDictionary *)formattedParams error:(NSError *__autoreleasing *)error {
  794. if ([mapRules[@"flattened"] boolValue] == NO) {
  795. prefix = [prefix stringByAppendingString:@".entry"];
  796. }
  797. NSArray *allKeysArray = [[values allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
  798. int index = 0;
  799. for (NSString *key in allKeysArray) {
  800. id value = values[key];
  801. [self serializeMember:key rules:mapRules[@"key"] prefix:[NSString stringWithFormat:@"%@.%d.%@",prefix,index+1,[self queryName:mapRules[@"key"] withDefaultName:@"key"]] formattedParams:formattedParams error:error];
  802. if (error && *error != nil) return NO;
  803. [self serializeMember:value rules:mapRules[@"value"] prefix:[NSString stringWithFormat:@"%@.%d.%@",prefix,index+1,[self queryName:mapRules[@"value"] withDefaultName:@"value"]] formattedParams:formattedParams error:error];
  804. if (error && *error != nil) return NO;
  805. index++;
  806. }
  807. return YES;
  808. }
  809. + (BOOL)serializeMember:(id)value rules:(AWSJSONDictionary *)shape prefix:(NSString *)prefix formattedParams:(NSMutableDictionary *)formattedParams error:(NSError *__autoreleasing *)error {
  810. if (prefix == nil) {
  811. prefix = @"";
  812. }
  813. NSString *rulesType = shape[@"type"];
  814. if ([rulesType isEqualToString:@"structure"]) {
  815. [self serializeStructure:value rules:shape prefix:[NSString stringWithFormat:@"%@.",prefix] formattedParams:formattedParams error:error];
  816. } else if ([rulesType isEqualToString:@"list"]) {
  817. [self serializeList:value rules:shape prefix:prefix formattedParams:formattedParams error:error];
  818. } else if ([rulesType isEqualToString:@"map"]) {
  819. [self serializeMap:value rules:shape prefix:prefix formattedParams:formattedParams error:error];
  820. } else if ([rulesType isEqualToString:@"timestamp"]) {
  821. NSDate *timeStampDate;
  822. //maybe a NSDate type or NSNumber type or NSString type
  823. if ([value isKindOfClass:[NSString class]]) {
  824. //try parse the string to NSDate first
  825. timeStampDate = [NSDate aws_dateFromString:value];
  826. //if failed, then parse it as double value
  827. if (!timeStampDate) {
  828. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[value doubleValue]];
  829. }
  830. } else if ([value isKindOfClass:[NSNumber class]]) {
  831. //need to convert to NSDate type
  832. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[value doubleValue]];
  833. } else if ([value isKindOfClass:[NSDate class]]) {
  834. timeStampDate = value;
  835. }
  836. //generate string presentation of timestamp
  837. //generate string presentation of timestamp
  838. NSString *timestampStr = @"";
  839. if ([shape[@"timestampFormat"] isEqualToString:@"iso8601"]) {
  840. timestampStr = [timeStampDate aws_stringValue:AWSDateISO8601DateFormat1];
  841. } else if ([shape[@"timestampFormat"] isEqualToString:@"unixTimestamp"]) {
  842. timestampStr = [NSString stringWithFormat:@"%.lf",[timeStampDate timeIntervalSince1970]];
  843. } else {
  844. //default timeStamp format
  845. timestampStr = [timeStampDate aws_stringValue:AWSDateISO8601DateFormat1];
  846. }
  847. if (!timestampStr) {
  848. timestampStr = @"";
  849. }
  850. formattedParams[prefix] = timestampStr;
  851. } else if ([rulesType isEqualToString:@"blob"]) {
  852. //encode NSData to Base64String
  853. if ([value isKindOfClass:[NSString class]]) {
  854. value = [value dataUsingEncoding:NSUTF8StringEncoding];
  855. }
  856. if ([value isKindOfClass:[NSData class]]) {
  857. NSString *base64encodedStr = [value base64EncodedStringWithOptions:0];
  858. formattedParams[prefix] = base64encodedStr?base64encodedStr:@"";
  859. } else {
  860. [self failWithCode:AWSQueryParamBuilderInvalidParameter description:@"'blob' value should be a NSData type." error:error];
  861. return NO;
  862. }
  863. } else if ([rulesType isEqualToString:@"boolean"]) {
  864. formattedParams[prefix] = [value boolValue]?@"true":@"false";
  865. } else {
  866. formattedParams[prefix] = value;
  867. }
  868. return YES;
  869. }
  870. + (NSString *)queryName:(NSDictionary *)shape withDefaultName:(NSString *)defaultName {
  871. return shape[@"locationName"]?shape[@"locationName"]:defaultName;
  872. }
  873. @end
  874. @implementation AWSEC2ParamBuilder
  875. + (BOOL)failWithCode:(NSInteger)code description:(NSString *)description error:(NSError *__autoreleasing *)error {
  876. if (error) {
  877. *error = [NSError errorWithDomain:AWSEC2ParamBuilderErrorDomain
  878. code:code
  879. userInfo:@{NSLocalizedDescriptionKey : description}];
  880. }
  881. return NO;
  882. }
  883. + (NSDictionary *)buildFormattedParams:(NSDictionary *)params
  884. actionName:(NSString *)actionName
  885. serviceDefinitionRule:(NSDictionary *)serviceDefinitionRule
  886. error:(NSError *__autoreleasing *)error {
  887. NSMutableDictionary *formattedParams = [NSMutableDictionary new];
  888. //add ActionName
  889. NSString *urlEncodedActionName = [actionName aws_stringWithURLEncoding];
  890. if (!urlEncodedActionName) {
  891. AWSDDLogError(@"actionName is nil!");
  892. [self failWithCode:AWSEC2ParamBuilderUndefinedActionRule description:@"actionName is nil" error:error];
  893. return nil;
  894. }
  895. [formattedParams setObject:urlEncodedActionName forKey:@"Action"];
  896. //add Version Number
  897. if (serviceDefinitionRule[@"metadata"] && serviceDefinitionRule[@"metadata"][@"apiVersion"] && [serviceDefinitionRule[@"metadata"][@"apiVersion"] isKindOfClass:[NSString class]]) {
  898. NSString *urlEncodedAPIVersion = [serviceDefinitionRule[@"metadata"][@"apiVersion"] aws_stringWithURLEncoding];
  899. if (urlEncodedAPIVersion) {
  900. [formattedParams setObject:urlEncodedAPIVersion forKey:@"Version"];
  901. } else {
  902. AWSDDLogError(@"can not encode APIVersion String:%@",urlEncodedAPIVersion);
  903. }
  904. } else {
  905. AWSDDLogError(@"can not find apiVersion keyword in definition file!");
  906. }
  907. if ([params count] == 0) {
  908. return formattedParams;
  909. }
  910. //add params
  911. NSDictionary *actionRule = [[[serviceDefinitionRule objectForKey:@"operations"] objectForKey:actionName] objectForKey:@"input"];
  912. NSDictionary *definitionRules = [serviceDefinitionRule objectForKey:@"shapes"];
  913. if (definitionRules == (id)[NSNull null] || [definitionRules count] == 0) {
  914. [self failWithCode:AWSEC2ParamBuilderDefinitionFileIsEmpty description:@"JSON definition File is empty or can not be found" error:error];
  915. return nil;
  916. }
  917. if ([actionRule count] == 0) {
  918. [self failWithCode:AWSEC2ParamBuilderUndefinedActionRule description:@"Invalid argument: actionRule is Empty" error:error];
  919. return nil;
  920. }
  921. AWSJSONDictionary *rules = [[AWSJSONDictionary alloc] initWithDictionary:actionRule JSONDefinitionRule:definitionRules];
  922. [AWSEC2ParamBuilder serializeStructure:params rules:rules prefix:@"" formattedParams:formattedParams error:error];
  923. return formattedParams;
  924. }
  925. + (BOOL)serializeStructure:(NSDictionary *)values rules:(AWSJSONDictionary *)structureRules prefix:(NSString *)prefix formattedParams:(NSMutableDictionary *)formattedParams error:(NSError *__autoreleasing *)error {
  926. for (NSString *name in values) {
  927. id value = values[name];
  928. AWSJSONDictionary *memberShape = structureRules[@"members"][name];
  929. if (memberShape && value) {
  930. [self serializeMember:value rules:memberShape prefix:[NSString stringWithFormat:@"%@%@",prefix,[self queryName:memberShape withDefaultName:name]] formattedParams:formattedParams error:error];
  931. if (error && *error != nil) {
  932. return NO;
  933. }
  934. }
  935. }
  936. return YES;
  937. }
  938. + (BOOL)serializeList:(NSArray *)values rules:(AWSJSONDictionary *)listRules prefix:(NSString *)prefix formattedParams:(NSMutableDictionary *)formattedParams error:(NSError *__autoreleasing *)error {
  939. if (values == nil) {
  940. if (prefix) {
  941. [formattedParams setObject:prefix forKey:@""];
  942. }
  943. return YES;
  944. }
  945. for (int i = 0; i < [values count]; i++) {
  946. id value = values[i];
  947. [self serializeMember:value rules:listRules[@"member"] prefix:[NSString stringWithFormat:@"%@.%d",prefix,i+1] formattedParams:formattedParams error:error];
  948. if (error && *error != nil) {
  949. return NO;
  950. }
  951. }
  952. return YES;
  953. }
  954. + (BOOL)serializeMember:(id)value rules:(AWSJSONDictionary *)shape prefix:(NSString *)prefix formattedParams:(NSMutableDictionary *)formattedParams error:(NSError *__autoreleasing *)error {
  955. if (prefix == nil) {
  956. prefix = @"";
  957. }
  958. NSString *rulesType = shape[@"type"];
  959. if ([rulesType isEqualToString:@"structure"]) {
  960. [self serializeStructure:value rules:shape prefix:[NSString stringWithFormat:@"%@.",prefix] formattedParams:formattedParams error:error];
  961. } else if ([rulesType isEqualToString:@"list"]) {
  962. [self serializeList:value rules:shape prefix:prefix formattedParams:formattedParams error:error];
  963. } else if ([rulesType isEqualToString:@"map"]) {
  964. // EC2 does not have any map type yet
  965. [self failWithCode:AWSEC2ParamBuilderInternalError description:@"serialize map type value has not been implemented yet" error:error];
  966. return NO;
  967. } else if ([rulesType isEqualToString:@"timestamp"]) {
  968. NSDate *timeStampDate;
  969. //maybe a NSDate type or NSNumber type or NSString type
  970. if ([value isKindOfClass:[NSString class]]) {
  971. //try parse the string to NSDate first
  972. timeStampDate = [NSDate aws_dateFromString:value];
  973. //if failed, then parse it as double value
  974. if (!timeStampDate) {
  975. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[value doubleValue]];
  976. }
  977. } else if ([value isKindOfClass:[NSNumber class]]) {
  978. //need to convert to NSDate type
  979. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[value doubleValue]];
  980. } else if ([value isKindOfClass:[NSDate class]]) {
  981. timeStampDate = value;
  982. }
  983. //generate string presentation of timestamp
  984. NSString *timestampStr = @"";
  985. if ([shape[@"timestampFormat"] isEqualToString:@"iso8601"]) {
  986. timestampStr = [timeStampDate aws_stringValue:AWSDateISO8601DateFormat1];
  987. } else if ([shape[@"timestampFormat"] isEqualToString:@"unixTimestamp"]) {
  988. timestampStr = [NSString stringWithFormat:@"%.lf",[timeStampDate timeIntervalSince1970]];
  989. } else {
  990. //default timeStamp format
  991. timestampStr = [timeStampDate aws_stringValue:AWSDateISO8601DateFormat1];
  992. }
  993. if (!timestampStr) {
  994. timestampStr = @"";
  995. }
  996. formattedParams[prefix] = timestampStr;
  997. } else if ([rulesType isEqualToString:@"blob"]) {
  998. //encode NSData to Base64String
  999. if ([value isKindOfClass:[NSString class]]) {
  1000. value = [value dataUsingEncoding:NSUTF8StringEncoding];
  1001. }
  1002. if ([value isKindOfClass:[NSData class]]) {
  1003. NSString *base64encodedStr = [value base64EncodedStringWithOptions:0];
  1004. formattedParams[prefix] = base64encodedStr?base64encodedStr:@"";
  1005. } else {
  1006. [self failWithCode:AWSEC2ParamBuilderInvalidParameter description:@"'blob' value should be a NSData type." error:error];
  1007. return NO;
  1008. }
  1009. } else if ([rulesType isEqualToString:@"boolean"]) {
  1010. formattedParams[prefix] = [value boolValue]?@"true":@"false";
  1011. } else {
  1012. formattedParams[prefix] = value;
  1013. }
  1014. return YES;
  1015. }
  1016. + (NSString *)queryName:(NSDictionary *)shape withDefaultName:(NSString *)defaultName {
  1017. NSString *resultStr = shape[@"queryName"]?shape[@"queryName"]:[self upperCaseFirstChar:shape[@"locationName"]];
  1018. return resultStr?resultStr:defaultName;
  1019. }
  1020. + (NSString *)upperCaseFirstChar:(NSString *) inputString {
  1021. if ([inputString length] < 1) {
  1022. return nil;
  1023. }
  1024. return [[[inputString substringToIndex:1] uppercaseString] stringByAppendingString: [inputString length]>1 ? [inputString substringFromIndex:1] : @"" ];
  1025. }
  1026. @end
  1027. @implementation AWSJSONBuilder
  1028. + (BOOL)failWithCode:(NSInteger)code description:(NSString *)description error:(NSError *__autoreleasing *)error {
  1029. if (error) {
  1030. *error = [NSError errorWithDomain:AWSJSONBuilderErrorDomain
  1031. code:code
  1032. userInfo:@{NSLocalizedDescriptionKey : description}];
  1033. }
  1034. return NO;
  1035. }
  1036. + (NSData *)jsonDataForDictionary:(NSDictionary *)params
  1037. actionName:(NSString *)actionName
  1038. serviceDefinitionRule:(NSDictionary *)serviceDefinitionRule
  1039. error:(NSError *__autoreleasing *)error {
  1040. id serializedJsonObject = [self buildJSONDictionary:params actionName:actionName serviceDefinitionRule:serviceDefinitionRule error:error];
  1041. if (!serializedJsonObject) {
  1042. serializedJsonObject = @{};
  1043. }
  1044. if ([NSJSONSerialization isValidJSONObject:serializedJsonObject] == NO) {
  1045. if ([serializedJsonObject isKindOfClass:[NSData class]]) {
  1046. return serializedJsonObject;
  1047. } else {
  1048. [self failWithCode:AWSJSONBuilderInvalidParameter description:[NSString stringWithFormat:@"serialized object is neither a valid json Object nor NSData object: %@",serializedJsonObject] error:error];
  1049. return nil;
  1050. }
  1051. } else {
  1052. NSData *bodyData = [NSJSONSerialization dataWithJSONObject:serializedJsonObject
  1053. options:0
  1054. error:error];
  1055. return bodyData;
  1056. }
  1057. }
  1058. + (NSDictionary *)buildJSONDictionary:(NSDictionary *)params
  1059. actionName:(NSString *)actionName
  1060. serviceDefinitionRule:(NSDictionary *)serviceDefinitionRule
  1061. error:(NSError *__autoreleasing *)error {
  1062. if ([params count] == 0) {
  1063. return nil;
  1064. }
  1065. NSDictionary *actionRule = [[[serviceDefinitionRule objectForKey:@"operations"] objectForKey:actionName] objectForKey:@"input"];
  1066. NSDictionary *definitionRules = [serviceDefinitionRule objectForKey:@"shapes"];
  1067. if (definitionRules == (id)[NSNull null] || [definitionRules count] == 0) {
  1068. AWSDDLogError(@"JSON definition File is empty or can not be found, will return un-serialized dictionary");
  1069. return params;
  1070. }
  1071. if ([actionRule count] == 0) {
  1072. [self failWithCode:AWSJSONBuilderUndefinedActionRule description:@"Invalid argument: actionRule is Empty" error:error];
  1073. return nil;
  1074. }
  1075. AWSJSONDictionary *rules = [[AWSJSONDictionary alloc] initWithDictionary:actionRule JSONDefinitionRule:definitionRules];
  1076. id resultParams = [self serializeMember:rules value:params isPayloadType:NO error:error];
  1077. return resultParams;
  1078. }
  1079. + (NSDictionary *)serializeStructure:(NSDictionary *)structureRules values:(NSDictionary *)values error:(NSError *__autoreleasing *)error {
  1080. NSMutableDictionary *data = [NSMutableDictionary new];
  1081. for (NSString *key in values) {
  1082. id value = values[key];
  1083. AWSJSONDictionary *memberShape = structureRules[@"members"][key];
  1084. if (memberShape[@"location"]) {
  1085. //It should be another location rather than body, will be process at different place
  1086. continue;
  1087. }
  1088. if (memberShape && value) {
  1089. NSString *name = memberShape[@"locationName"]?memberShape[@"locationName"]:key;
  1090. data[name] = [self serializeMember:memberShape value:value isPayloadType:NO error:error];
  1091. }
  1092. }
  1093. return data;
  1094. }
  1095. + (NSArray *)serializeList:(NSDictionary *)listRules values:(NSArray *)values error:(NSError *__autoreleasing *)error {
  1096. NSMutableArray *dataArray = [NSMutableArray new];
  1097. for (id value in values) {
  1098. [dataArray addObject:[self serializeMember:listRules[@"member"] value:value isPayloadType:NO error:error]];
  1099. }
  1100. return dataArray;
  1101. }
  1102. + (NSDictionary *)serializeMap:(NSDictionary *)mapRules values:(NSDictionary *)values error:(NSError *__autoreleasing *)error {
  1103. NSMutableDictionary *data = [NSMutableDictionary new];
  1104. for (NSString *key in values) {
  1105. id value = values[key];
  1106. data[key] = [self serializeMember:mapRules[@"value"] value:value isPayloadType:NO error:error];
  1107. }
  1108. return data;
  1109. }
  1110. + (id)serializeMember:(NSDictionary *)shape value:(id)value isPayloadType:(BOOL)isPayloadType error:(NSError *__autoreleasing *)error {
  1111. NSString *payloadMemberName = shape[@"payload"];
  1112. if (payloadMemberName) {
  1113. id payload = value[payloadMemberName];
  1114. if (payload) {
  1115. AWSJSONDictionary *structureMembersRule = shape[@"members"]?shape[@"members"]:@{};
  1116. AWSJSONDictionary *payloadMemberRules = structureMembersRule[payloadMemberName];
  1117. return [self serializeMember:payloadMemberRules value:payload isPayloadType:YES error:error];
  1118. }
  1119. }
  1120. NSString *rulesType = shape[@"type"];
  1121. if ([rulesType isEqualToString:@"structure"]) {
  1122. if (![value isKindOfClass:[NSDictionary class]]) {
  1123. if (![value isKindOfClass:[NSNull class]]) {
  1124. [self failWithCode:AWSJSONBuilderInvalidParameter description:[NSString stringWithFormat:@"a structure input should be a dictionary but got:%@",value] error:error];
  1125. }
  1126. return @{};
  1127. } else {
  1128. return [self serializeStructure:shape values:value error:error];
  1129. }
  1130. } else if ([rulesType isEqualToString:@"list"]) {
  1131. if (![value isKindOfClass:[NSArray class]]) {
  1132. if (![value isKindOfClass:[NSNull class]]) {
  1133. [self failWithCode:AWSJSONBuilderInvalidParameter description:[NSString stringWithFormat:@"a list input should be an array but got:%@",value] error:error];
  1134. }
  1135. return @[];
  1136. } else {
  1137. return [self serializeList:shape values:value error:error];
  1138. }
  1139. } else if ([rulesType isEqualToString:@"map"]) {
  1140. if (![value isKindOfClass:[NSDictionary class]]) {
  1141. if (![value isKindOfClass:[NSNull class]]) {
  1142. [self failWithCode:AWSJSONBuilderInvalidParameter description:[NSString stringWithFormat:@"a map input should be a dictionary but got:%@",value] error:error];
  1143. }
  1144. return @{};
  1145. } else {
  1146. return [self serializeMap:shape values:value error:error];
  1147. }
  1148. } else if ([rulesType isEqualToString:@"timestamp"]) {
  1149. NSDate *timeStampDate;
  1150. //maybe a NSDate type or NSNumber type or NSString type
  1151. if ([value isKindOfClass:[NSString class]]) {
  1152. //try parse the string to NSDate first
  1153. timeStampDate = [NSDate aws_dateFromString:value];
  1154. //if failed, then parse it as double value
  1155. if (!timeStampDate) {
  1156. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[value doubleValue]];
  1157. }
  1158. } else if ([value isKindOfClass:[NSNumber class]]) {
  1159. //need to convert to NSDate type
  1160. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[value doubleValue]];
  1161. } else if ([value isKindOfClass:[NSDate class]]) {
  1162. timeStampDate = value;
  1163. }
  1164. return [NSNumber numberWithDouble:[timeStampDate timeIntervalSince1970]];
  1165. } else if ([rulesType isEqualToString:@"blob"]) {
  1166. //encode NSData to Base64String
  1167. if ([value isKindOfClass:[NSString class]]) {
  1168. value = [value dataUsingEncoding:NSUTF8StringEncoding];
  1169. }
  1170. if ([value isKindOfClass:[NSData class]]) {
  1171. if (isPayloadType) {
  1172. //Do not base64 encoding if it is payload type
  1173. return value;
  1174. } else {
  1175. NSString *base64encodedStr = [value base64EncodedStringWithOptions:0];
  1176. return base64encodedStr?base64encodedStr:@"";
  1177. }
  1178. } else {
  1179. [self failWithCode:AWSJSONBuilderInvalidParameter description:@"'blob' value should be a NSData type." error:error];
  1180. return @"";
  1181. }
  1182. } else {
  1183. return value;
  1184. }
  1185. }
  1186. @end
  1187. @implementation AWSJSONParser
  1188. + (BOOL)failWithCode:(NSInteger)code description:(NSString *)description error:(NSError *__autoreleasing *)error {
  1189. if (error) {
  1190. *error = [NSError errorWithDomain:AWSJSONParserErrorDomain
  1191. code:code
  1192. userInfo:@{NSLocalizedDescriptionKey : description}];
  1193. }
  1194. return NO;
  1195. }
  1196. + (NSDictionary *)dictionaryForJsonData:(NSData *)data
  1197. response:(NSHTTPURLResponse *)response
  1198. actionName:(NSString *)actionName
  1199. serviceDefinitionRule:(NSDictionary *)serviceDefinitionRule
  1200. error:(NSError *__autoreleasing *)error {
  1201. if (!data) {
  1202. return [NSMutableDictionary new];
  1203. }
  1204. // Amazon Lambda may return non-array/non-dictionary top level objects.
  1205. // They are valid JSON texts according to RFC 7159 and ECMA 404.
  1206. // (RFC 4627 was replaced with RFC 7159 in March 2014.)
  1207. // You need to pass NSJSONReadingAllowFragments here, otherwise, they may fail.
  1208. id result = [NSJSONSerialization JSONObjectWithData:data
  1209. options:NSJSONReadingAllowFragments
  1210. error:error];
  1211. NSDictionary *actionRule = [[[serviceDefinitionRule objectForKey:@"operations"] objectForKey:actionName] objectForKey:@"output"];
  1212. if (actionRule == (id)[NSNull null]) {
  1213. actionRule = @{};
  1214. }
  1215. NSDictionary *definitionRules = [serviceDefinitionRule objectForKey:@"shapes"];
  1216. if (definitionRules == (id)[NSNull null]) {
  1217. definitionRules = @{};
  1218. }
  1219. if ([definitionRules count] == 0) {
  1220. AWSDDLogError(@"JSON definition File is empty or can not be found, will return un-serialized dictionary");
  1221. return result;
  1222. }
  1223. //if the response is error message, just return
  1224. if (response.statusCode/100 != 2) {
  1225. return result;
  1226. }
  1227. AWSJSONDictionary *rules = [[AWSJSONDictionary alloc] initWithDictionary:actionRule JSONDefinitionRule:definitionRules];
  1228. //check if has payload tag.
  1229. NSString *isPayloadData = rules[@"payload"];
  1230. NSMutableDictionary *parsedData = [NSMutableDictionary new];
  1231. if (isPayloadData) {
  1232. NSString *shapeName = [rules[@"members"][isPayloadData] objectForKey:@"shape"];
  1233. //
  1234. // Check if we should apply additional serialization; for streaming
  1235. // types or the 'JsonDocument' shape, no additional serialization will
  1236. // be applied and the data will be returned as-is in the response.
  1237. // The 'JsonDocument' shape is used by the AWSIoT service.
  1238. //
  1239. if ((rules[@"members"][isPayloadData][@"streaming"]) || ([shapeName isEqual:@"JsonDocument"]) || ([shapeName isEqual:@"BlobStream"])) {
  1240. parsedData[isPayloadData] = data;
  1241. if (error) *error = nil;
  1242. return parsedData;
  1243. }
  1244. rules = rules[isPayloadData][@"members"];
  1245. parsedData[isPayloadData] = [self serializeMember:rules value:result target:nil error:error];
  1246. } else {
  1247. parsedData = [self serializeMember:rules value:result target:nil error:error];
  1248. }
  1249. return parsedData;
  1250. }
  1251. + (NSString *)findMemberName:(NSString*)locationName structureRules:(NSDictionary *)structureRules {
  1252. for (NSString *aMember in structureRules[@"members"]) {
  1253. NSDictionary *memberShape = structureRules[@"members"][aMember];
  1254. if ([memberShape[@"locationName"] isEqualToString:locationName]) {
  1255. return aMember;
  1256. }
  1257. }
  1258. return locationName;
  1259. }
  1260. + (id)serializeStructure:(NSDictionary *)structureRules values:(NSDictionary *)values target:(id)target error:(NSError *__autoreleasing *)error{
  1261. if (!target) {
  1262. target = [NSMutableDictionary new];
  1263. }
  1264. for (NSString *serialized_name in values) {
  1265. id value = values[serialized_name];
  1266. NSString *memberName = [self findMemberName:serialized_name structureRules:structureRules];
  1267. AWSJSONDictionary *memberShape = structureRules[@"members"][memberName];
  1268. if (memberShape && value) {
  1269. // NSString *name = memberShape[@"locationName"]?memberShape[@"locationName"]:serialized_name;
  1270. target[memberName] = [self serializeMember:memberShape value:value target:nil error:(NSError *__autoreleasing *)error];
  1271. }
  1272. }
  1273. return target;
  1274. }
  1275. + (NSMutableArray *)serializeList:(NSDictionary *)listRules values:(NSDictionary *)values target:(id)target error:(NSError *__autoreleasing *)error{
  1276. if (!target) {
  1277. target = [NSMutableArray new];
  1278. }
  1279. for (NSString *value in values) {
  1280. [target addObject:[self serializeMember:listRules[@"member"] value:value target:nil error:(NSError *__autoreleasing *)error]];
  1281. }
  1282. return target;
  1283. }
  1284. + (NSMutableDictionary *) serializeMap:(NSDictionary *)mapRules values:(NSDictionary *)values target:(id)target error:(NSError *__autoreleasing *)error{
  1285. if (!target) {
  1286. target = [NSMutableDictionary new];
  1287. }
  1288. for (NSString *key in values) {
  1289. id value = values[key];
  1290. target[key] = [self serializeMember:mapRules[@"value"] value:value target:nil error:(NSError *__autoreleasing *)error];
  1291. }
  1292. return target;
  1293. }
  1294. + (id)serializeMember:(NSDictionary *)shape value:(id)value target:(id)target error:(NSError *__autoreleasing *)error{
  1295. if (!value) {
  1296. return nil;
  1297. }
  1298. NSString *rulesType = shape[@"type"];
  1299. if ([rulesType isEqualToString:@"structure"]) {
  1300. if (![value isKindOfClass:[NSDictionary class]]) {
  1301. if (![value isKindOfClass:[NSNull class]]) {
  1302. [self failWithCode:AWSJSONParserInvalidParameter description:[NSString stringWithFormat:@"a structure input should be a dictionary but got:%@",value] error:error];
  1303. }
  1304. return @{};
  1305. } else {
  1306. return [self serializeStructure:shape values:value target:target error:error];
  1307. }
  1308. } else if ([rulesType isEqualToString:@"list"]) {
  1309. if (![value isKindOfClass:[NSArray class]]) {
  1310. if (![value isKindOfClass:[NSNull class]]) {
  1311. [self failWithCode:AWSJSONParserInvalidParameter description:[NSString stringWithFormat:@"a list input should be an array but got:%@",value] error:error];
  1312. }
  1313. return @[];
  1314. } else {
  1315. return [self serializeList:shape values:value target:target error:error];
  1316. }
  1317. } else if ([rulesType isEqualToString:@"map"]) {
  1318. if (![value isKindOfClass:[NSDictionary class]]) {
  1319. if (![value isKindOfClass:[NSNull class]]) {
  1320. [self failWithCode:AWSJSONParserInvalidParameter description:[NSString stringWithFormat:@"a map input should be a dictionary but got:%@",value] error:error];
  1321. }
  1322. return @{};
  1323. } else {
  1324. return [self serializeMap:shape values:value target:target error:error];
  1325. }
  1326. } else if ([rulesType isEqualToString:@"timestamp"]) {
  1327. NSDate *timeStampDate;
  1328. //maybe a NSDate type or NSNumber type or NSString type
  1329. if ([value isKindOfClass:[NSString class]]) {
  1330. //try parse the string to NSDate first
  1331. timeStampDate = [NSDate aws_dateFromString:value];
  1332. //if failed, then parse it as double value
  1333. if (!timeStampDate) {
  1334. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[value doubleValue]];
  1335. }
  1336. } else if ([value isKindOfClass:[NSNumber class]]) {
  1337. //need to convert to NSDate type
  1338. timeStampDate = [NSDate dateWithTimeIntervalSince1970:[value doubleValue]];
  1339. } else if ([value isKindOfClass:[NSDate class]]) {
  1340. timeStampDate = value;
  1341. }
  1342. return [NSNumber numberWithDouble:[timeStampDate timeIntervalSince1970]];
  1343. } else if ([rulesType isEqualToString:@"blob"]) {
  1344. //decode Base64Str to NSData
  1345. if ([value isKindOfClass:[NSString class]]) {
  1346. NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:value options:0];
  1347. //return origin string value if can not be encoded.
  1348. return decodedData?decodedData:value;
  1349. } else {
  1350. [self failWithCode:AWSJSONParserInvalidParameter description:@"blob value should be NSString type." error:error];
  1351. return [NSData new];
  1352. }
  1353. } else {
  1354. return value;
  1355. }
  1356. }
  1357. @end