12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138 |
- #import "ASIHTTPRequest.h"
- #if TARGET_OS_IPHONE
- #import "Reachability.h"
- #import "ASIAuthenticationDialog.h"
- #import <MobileCoreServices/MobileCoreServices.h>
- #else
- #import <SystemConfiguration/SystemConfiguration.h>
- #endif
- #import "ASIInputStream.h"
- #import "ASIDataDecompressor.h"
- #import "ASIDataCompressor.h"
- NSString *ASIHTTPRequestVersion = @"v1.8.1-61 2011-09-19";
- static NSString *defaultUserAgent = nil;
- NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
- static NSString *ASIHTTPRequestRunLoopMode = @"ASIHTTPRequestRunLoopMode";
- static const CFOptionFlags kNetworkEvents = kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred;
- static NSMutableArray *sessionCredentialsStore = nil;
- static NSMutableArray *sessionProxyCredentialsStore = nil;
- static NSRecursiveLock *sessionCredentialsLock = nil;
- static NSMutableArray *sessionCookies = nil;
- const int RedirectionLimit = 5;
- static NSTimeInterval defaultTimeOutSeconds = 10;
- static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventType type, void *clientCallBackInfo) {
- [((ASIHTTPRequest*)clientCallBackInfo) handleNetworkEvent: type];
- }
- static NSRecursiveLock *progressLock;
- static NSError *ASIRequestCancelledError;
- static NSError *ASIRequestTimedOutError;
- static NSError *ASIAuthenticationError;
- static NSError *ASIUnableToCreateRequestError;
- static NSError *ASITooMuchRedirectionError;
- static NSMutableArray *bandwidthUsageTracker = nil;
- static unsigned long averageBandwidthUsedPerSecond = 0;
- static unsigned int nextConnectionNumberToCreate = 0;
- static NSMutableArray *persistentConnectionsPool = nil;
- static NSRecursiveLock *connectionsLock = nil;
- static unsigned int nextRequestID = 0;
- static unsigned long bandwidthUsedInLastSecond = 0;
- static NSDate *bandwidthMeasurementDate = nil;
- static NSLock *bandwidthThrottlingLock = nil;
- static unsigned long maxBandwidthPerSecond = 0;
- unsigned long const ASIWWANBandwidthThrottleAmount = 14800;
- #if TARGET_OS_IPHONE
- static BOOL isBandwidthThrottled = NO;
- static BOOL shouldThrottleBandwidthForWWANOnly = NO;
- #endif
- static NSRecursiveLock *sessionCookiesLock = nil;
- static NSRecursiveLock *delegateAuthenticationLock = nil;
- static NSDate *throttleWakeUpTime = nil;
- static id <ASICacheDelegate> defaultCache = nil;
- static unsigned int runningRequestCount = 0;
- static BOOL shouldUpdateNetworkActivityIndicator = YES;
- static NSThread *networkThread = nil;
- static NSOperationQueue *sharedQueue = nil;
- @interface ASIHTTPRequest ()
- - (void)cancelLoad;
- - (void)destroyReadStream;
- - (void)scheduleReadStream;
- - (void)unscheduleReadStream;
- - (BOOL)willAskDelegateForCredentials;
- - (BOOL)willAskDelegateForProxyCredentials;
- - (void)askDelegateForProxyCredentials;
- - (void)askDelegateForCredentials;
- - (void)failAuthentication;
- + (void)measureBandwidthUsage;
- + (void)recordBandwidthUsage;
- - (void)startRequest;
- - (void)updateStatus:(NSTimer *)timer;
- - (void)checkRequestStatus;
- - (void)reportFailure;
- - (void)reportFinished;
- - (void)markAsFinished;
- - (void)performRedirect;
- - (BOOL)shouldTimeOut;
- - (BOOL)willRedirect;
- - (BOOL)willAskDelegateToConfirmRedirect;
- + (void)performInvocation:(NSInvocation *)invocation onTarget:(id *)target releasingObject:(id)objectToRelease;
- + (void)hideNetworkActivityIndicatorAfterDelay;
- + (void)hideNetworkActivityIndicatorIfNeeeded;
- + (void)runRequests;
- - (BOOL)configureProxies;
- - (void)fetchPACFile;
- - (void)finishedDownloadingPACFile:(ASIHTTPRequest *)theRequest;
- - (void)runPACScript:(NSString *)script;
- - (void)timeOutPACRead;
- - (void)useDataFromCache;
- - (void)updatePartialDownloadSize;
- #if TARGET_OS_IPHONE
- + (void)registerForNetworkReachabilityNotifications;
- + (void)unsubscribeFromNetworkReachabilityNotifications;
- + (void)reachabilityChanged:(NSNotification *)note;
- #endif
- #if NS_BLOCKS_AVAILABLE
- - (void)performBlockOnMainThread:(ASIBasicBlock)block;
- - (void)releaseBlocksOnMainThread;
- + (void)releaseBlocks:(NSArray *)blocks;
- - (void)callBlock:(ASIBasicBlock)block;
- #endif
- @property (assign) BOOL complete;
- @property (retain) NSArray *responseCookies;
- @property (assign) int responseStatusCode;
- @property (retain, nonatomic) NSDate *lastActivityTime;
- @property (assign) unsigned long long partialDownloadSize;
- @property (assign, nonatomic) unsigned long long uploadBufferSize;
- @property (retain, nonatomic) NSOutputStream *postBodyWriteStream;
- @property (retain, nonatomic) NSInputStream *postBodyReadStream;
- @property (assign, nonatomic) unsigned long long lastBytesRead;
- @property (assign, nonatomic) unsigned long long lastBytesSent;
- @property (atomic, retain) NSRecursiveLock *cancelledLock;
- @property (retain, nonatomic) NSOutputStream *fileDownloadOutputStream;
- @property (retain, nonatomic) NSOutputStream *inflatedFileDownloadOutputStream;
- @property (assign) int authenticationRetryCount;
- @property (assign) int proxyAuthenticationRetryCount;
- @property (assign, nonatomic) BOOL updatedProgress;
- @property (assign, nonatomic) BOOL needsRedirect;
- @property (assign, nonatomic) int redirectCount;
- @property (retain, nonatomic) NSData *compressedPostBody;
- @property (retain, nonatomic) NSString *compressedPostBodyFilePath;
- @property (retain) NSString *authenticationRealm;
- @property (retain) NSString *proxyAuthenticationRealm;
- @property (retain) NSString *responseStatusMessage;
- @property (assign) BOOL inProgress;
- @property (assign) int retryCount;
- @property (atomic, assign) BOOL willRetryRequest;
- @property (assign) BOOL connectionCanBeReused;
- @property (retain, nonatomic) NSMutableDictionary *connectionInfo;
- @property (retain, nonatomic) NSInputStream *readStream;
- @property (assign) ASIAuthenticationState authenticationNeeded;
- @property (assign, nonatomic) BOOL readStreamIsScheduled;
- @property (assign, nonatomic) BOOL downloadComplete;
- @property (retain) NSNumber *requestID;
- @property (assign, nonatomic) NSString *runLoopMode;
- @property (retain, nonatomic) NSTimer *statusTimer;
- @property (assign) BOOL didUseCachedResponse;
- @property (retain, nonatomic) NSURL *redirectURL;
- @property (assign, nonatomic) BOOL isPACFileRequest;
- @property (retain, nonatomic) ASIHTTPRequest *PACFileRequest;
- @property (retain, nonatomic) NSInputStream *PACFileReadStream;
- @property (retain, nonatomic) NSMutableData *PACFileData;
- @property (assign, nonatomic, setter=setSynchronous:) BOOL isSynchronous;
- @end
- @implementation ASIHTTPRequest
- #pragma mark init / dealloc
- + (void)initialize
- {
- if (self == [ASIHTTPRequest class]) {
- persistentConnectionsPool = [[NSMutableArray alloc] init];
- connectionsLock = [[NSRecursiveLock alloc] init];
- progressLock = [[NSRecursiveLock alloc] init];
- bandwidthThrottlingLock = [[NSLock alloc] init];
- sessionCookiesLock = [[NSRecursiveLock alloc] init];
- sessionCredentialsLock = [[NSRecursiveLock alloc] init];
- delegateAuthenticationLock = [[NSRecursiveLock alloc] init];
- bandwidthUsageTracker = [[NSMutableArray alloc] initWithCapacity:5];
- ASIRequestTimedOutError = [[NSError alloc] initWithDomain:NetworkRequestErrorDomain code:ASIRequestTimedOutErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request timed out",NSLocalizedDescriptionKey,nil]];
- ASIAuthenticationError = [[NSError alloc] initWithDomain:NetworkRequestErrorDomain code:ASIAuthenticationErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Authentication needed",NSLocalizedDescriptionKey,nil]];
- ASIRequestCancelledError = [[NSError alloc] initWithDomain:NetworkRequestErrorDomain code:ASIRequestCancelledErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request was cancelled",NSLocalizedDescriptionKey,nil]];
- ASIUnableToCreateRequestError = [[NSError alloc] initWithDomain:NetworkRequestErrorDomain code:ASIUnableToCreateRequestErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to create request (bad url?)",NSLocalizedDescriptionKey,nil]];
- ASITooMuchRedirectionError = [[NSError alloc] initWithDomain:NetworkRequestErrorDomain code:ASITooMuchRedirectionErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request failed because it redirected too many times",NSLocalizedDescriptionKey,nil]];
- sharedQueue = [[NSOperationQueue alloc] init];
- [sharedQueue setMaxConcurrentOperationCount:4];
- }
- }
- - (id)initWithURL:(NSURL *)newURL
- {
- self = [self init];
- [self setRequestMethod:@"GET"];
- [self setRunLoopMode:NSDefaultRunLoopMode];
- [self setShouldAttemptPersistentConnection:YES];
- [self setPersistentConnectionTimeoutSeconds:60.0];
- [self setShouldPresentCredentialsBeforeChallenge:YES];
- [self setShouldRedirect:YES];
- [self setShowAccurateProgress:YES];
- [self setShouldResetDownloadProgress:YES];
- [self setShouldResetUploadProgress:YES];
- [self setAllowCompressedResponse:YES];
- [self setShouldWaitToInflateCompressedResponses:YES];
- [self setDefaultResponseEncoding:NSISOLatin1StringEncoding];
- [self setShouldPresentProxyAuthenticationDialog:YES];
-
- [self setTimeOutSeconds:[ASIHTTPRequest defaultTimeOutSeconds]];
- [self setUseSessionPersistence:YES];
- [self setUseCookiePersistence:YES];
- [self setValidatesSecureCertificate:YES];
- [self setRequestCookies:[[[NSMutableArray alloc] init] autorelease]];
- [self setDidStartSelector:@selector(requestStarted:)];
- [self setDidReceiveResponseHeadersSelector:@selector(request:didReceiveResponseHeaders:)];
- [self setWillRedirectSelector:@selector(request:willRedirectToURL:)];
- [self setDidFinishSelector:@selector(requestFinished:)];
- [self setDidFailSelector:@selector(requestFailed:)];
- [self setDidReceiveDataSelector:@selector(request:didReceiveData:)];
- [self setURL:newURL];
- [self setCancelledLock:[[[NSRecursiveLock alloc] init] autorelease]];
- [self setDownloadCache:[[self class] defaultCache]];
- return self;
- }
- + (id)requestWithURL:(NSURL *)newURL
- {
- return [[[self alloc] initWithURL:newURL] autorelease];
- }
- + (id)requestWithURL:(NSURL *)newURL usingCache:(id <ASICacheDelegate>)cache
- {
- return [self requestWithURL:newURL usingCache:cache andCachePolicy:ASIUseDefaultCachePolicy];
- }
- + (id)requestWithURL:(NSURL *)newURL usingCache:(id <ASICacheDelegate>)cache andCachePolicy:(ASICachePolicy)policy
- {
- ASIHTTPRequest *request = [[[self alloc] initWithURL:newURL] autorelease];
- [request setDownloadCache:cache];
- [request setCachePolicy:policy];
- return request;
- }
- - (void)dealloc
- {
- [self setAuthenticationNeeded:ASINoAuthenticationNeededYet];
- if (requestAuthentication) {
- CFRelease(requestAuthentication);
- }
- if (proxyAuthentication) {
- CFRelease(proxyAuthentication);
- }
- if (request) {
- CFRelease(request);
- }
- if (clientCertificateIdentity) {
- CFRelease(clientCertificateIdentity);
- }
- [self cancelLoad];
- [redirectURL release];
- [statusTimer invalidate];
- [statusTimer release];
- [queue release];
- [userInfo release];
- [postBody release];
- [compressedPostBody release];
- [error release];
- [requestHeaders release];
- [requestCookies release];
- [downloadDestinationPath release];
- [temporaryFileDownloadPath release];
- [temporaryUncompressedDataDownloadPath release];
- [fileDownloadOutputStream release];
- [inflatedFileDownloadOutputStream release];
- [username release];
- [password release];
- [domain release];
- [authenticationRealm release];
- [authenticationScheme release];
- [requestCredentials release];
- [proxyHost release];
- [proxyType release];
- [proxyUsername release];
- [proxyPassword release];
- [proxyDomain release];
- [proxyAuthenticationRealm release];
- [proxyAuthenticationScheme release];
- [proxyCredentials release];
- [url release];
- [originalURL release];
- [lastActivityTime release];
- [responseCookies release];
- [rawResponseData release];
- [responseHeaders release];
- [requestMethod release];
- [cancelledLock release];
- [postBodyFilePath release];
- [compressedPostBodyFilePath release];
- [postBodyWriteStream release];
- [postBodyReadStream release];
- [PACurl release];
- [clientCertificates release];
- [responseStatusMessage release];
- [connectionInfo release];
- [requestID release];
- [dataDecompressor release];
- [userAgentString release];
- #if NS_BLOCKS_AVAILABLE
- [self releaseBlocksOnMainThread];
- #endif
- [super dealloc];
- }
- #if NS_BLOCKS_AVAILABLE
- - (void)releaseBlocksOnMainThread
- {
- NSMutableArray *blocks = [NSMutableArray array];
- if (completionBlock) {
- [blocks addObject:completionBlock];
- [completionBlock release];
- completionBlock = nil;
- }
- if (failureBlock) {
- [blocks addObject:failureBlock];
- [failureBlock release];
- failureBlock = nil;
- }
- if (startedBlock) {
- [blocks addObject:startedBlock];
- [startedBlock release];
- startedBlock = nil;
- }
- if (headersReceivedBlock) {
- [blocks addObject:headersReceivedBlock];
- [headersReceivedBlock release];
- headersReceivedBlock = nil;
- }
- if (bytesReceivedBlock) {
- [blocks addObject:bytesReceivedBlock];
- [bytesReceivedBlock release];
- bytesReceivedBlock = nil;
- }
- if (bytesSentBlock) {
- [blocks addObject:bytesSentBlock];
- [bytesSentBlock release];
- bytesSentBlock = nil;
- }
- if (downloadSizeIncrementedBlock) {
- [blocks addObject:downloadSizeIncrementedBlock];
- [downloadSizeIncrementedBlock release];
- downloadSizeIncrementedBlock = nil;
- }
- if (uploadSizeIncrementedBlock) {
- [blocks addObject:uploadSizeIncrementedBlock];
- [uploadSizeIncrementedBlock release];
- uploadSizeIncrementedBlock = nil;
- }
- if (dataReceivedBlock) {
- [blocks addObject:dataReceivedBlock];
- [dataReceivedBlock release];
- dataReceivedBlock = nil;
- }
- if (proxyAuthenticationNeededBlock) {
- [blocks addObject:proxyAuthenticationNeededBlock];
- [proxyAuthenticationNeededBlock release];
- proxyAuthenticationNeededBlock = nil;
- }
- if (authenticationNeededBlock) {
- [blocks addObject:authenticationNeededBlock];
- [authenticationNeededBlock release];
- authenticationNeededBlock = nil;
- }
- if (requestRedirectedBlock) {
- [blocks addObject:requestRedirectedBlock];
- [requestRedirectedBlock release];
- requestRedirectedBlock = nil;
- }
- [[self class] performSelectorOnMainThread:@selector(releaseBlocks:) withObject:blocks waitUntilDone:[NSThread isMainThread]];
- }
- + (void)releaseBlocks:(NSArray *)blocks
- {
-
- }
- #endif
- #pragma mark setup request
- - (void)addRequestHeader:(NSString *)header value:(NSString *)value
- {
- if (!requestHeaders) {
- [self setRequestHeaders:[NSMutableDictionary dictionaryWithCapacity:1]];
- }
- [requestHeaders setObject:value forKey:header];
- }
- - (void)buildPostBody
- {
- if ([self haveBuiltPostBody]) {
- return;
- }
-
-
- if ([self postBodyFilePath]) {
-
-
- if ([self postBodyWriteStream]) {
- [[self postBodyWriteStream] close];
- [self setPostBodyWriteStream:nil];
- }
-
- NSString *path;
- if ([self shouldCompressRequestBody]) {
- if (![self compressedPostBodyFilePath]) {
- [self setCompressedPostBodyFilePath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]];
-
- NSError *err = nil;
- if (![ASIDataCompressor compressDataFromFile:[self postBodyFilePath] toFile:[self compressedPostBodyFilePath] error:&err]) {
- [self failWithError:err];
- return;
- }
- }
- path = [self compressedPostBodyFilePath];
- } else {
- path = [self postBodyFilePath];
- }
- NSError *err = nil;
- [self setPostLength:[[[[[NSFileManager alloc] init] autorelease] attributesOfItemAtPath:path error:&err] fileSize]];
- if (err) {
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIFileManagementError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Failed to get attributes for file at path '%@'",path],NSLocalizedDescriptionKey,error,NSUnderlyingErrorKey,nil]]];
- return;
- }
-
-
- } else {
- if ([self shouldCompressRequestBody]) {
- NSError *err = nil;
- NSData *compressedBody = [ASIDataCompressor compressData:[self postBody] error:&err];
- if (err) {
- [self failWithError:err];
- return;
- }
- [self setCompressedPostBody:compressedBody];
- [self setPostLength:[[self compressedPostBody] length]];
- } else {
- [self setPostLength:[[self postBody] length]];
- }
- }
-
- if ([self postLength] > 0) {
- if ([requestMethod isEqualToString:@"GET"] || [requestMethod isEqualToString:@"DELETE"] || [requestMethod isEqualToString:@"HEAD"]) {
- [self setRequestMethod:@"POST"];
- }
- [self addRequestHeader:@"Content-Length" value:[NSString stringWithFormat:@"%llu",[self postLength]]];
- }
- [self setHaveBuiltPostBody:YES];
- }
- - (void)setupPostBody
- {
- if ([self shouldStreamPostDataFromDisk]) {
- if (![self postBodyFilePath]) {
- [self setPostBodyFilePath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]];
- [self setDidCreateTemporaryPostDataFile:YES];
- }
- if (![self postBodyWriteStream]) {
- [self setPostBodyWriteStream:[[[NSOutputStream alloc] initToFileAtPath:[self postBodyFilePath] append:NO] autorelease]];
- [[self postBodyWriteStream] open];
- }
- } else {
- if (![self postBody]) {
- [self setPostBody:[[[NSMutableData alloc] init] autorelease]];
- }
- }
- }
- - (void)appendPostData:(NSData *)data
- {
- [self setupPostBody];
- if ([data length] == 0) {
- return;
- }
- if ([self shouldStreamPostDataFromDisk]) {
- [[self postBodyWriteStream] write:[data bytes] maxLength:[data length]];
- } else {
- [[self postBody] appendData:data];
- }
- }
- - (void)appendPostDataFromFile:(NSString *)file
- {
- [self setupPostBody];
- NSInputStream *stream = [[[NSInputStream alloc] initWithFileAtPath:file] autorelease];
- [stream open];
- while ([stream hasBytesAvailable]) {
-
- unsigned char buffer[1024*256];
- NSInteger bytesRead = [stream read:buffer maxLength:sizeof(buffer)];
- if (bytesRead == 0) {
-
- break;
- } else if (bytesRead < 0) {
-
- break;
- }
- if ([self shouldStreamPostDataFromDisk]) {
- [[self postBodyWriteStream] write:buffer maxLength:(NSUInteger)bytesRead];
- } else {
- [[self postBody] appendData:[NSData dataWithBytes:buffer length:(NSUInteger)bytesRead]];
- }
- }
- [stream close];
- }
- - (NSString *)requestMethod
- {
- [[self cancelledLock] lock];
- NSString *m = requestMethod;
- [[self cancelledLock] unlock];
- return m;
- }
- - (void)setRequestMethod:(NSString *)newRequestMethod
- {
- [[self cancelledLock] lock];
- if (requestMethod != newRequestMethod) {
- [requestMethod release];
- requestMethod = [newRequestMethod retain];
- if ([requestMethod isEqualToString:@"POST"] || [requestMethod isEqualToString:@"PUT"] || [postBody length] || postBodyFilePath) {
- [self setShouldAttemptPersistentConnection:NO];
- }
- }
- [[self cancelledLock] unlock];
- }
- - (NSURL *)url
- {
- [[self cancelledLock] lock];
- NSURL *u = url;
- [[self cancelledLock] unlock];
- return u;
- }
- - (void)setURL:(NSURL *)newURL
- {
- [[self cancelledLock] lock];
- if ([newURL isEqual:[self url]]) {
- [[self cancelledLock] unlock];
- return;
- }
- [url release];
- url = [newURL retain];
- if (requestAuthentication) {
- CFRelease(requestAuthentication);
- requestAuthentication = NULL;
- }
- if (proxyAuthentication) {
- CFRelease(proxyAuthentication);
- proxyAuthentication = NULL;
- }
- if (request) {
- CFRelease(request);
- request = NULL;
- }
- [self setRedirectURL:nil];
- [[self cancelledLock] unlock];
- }
- - (id)delegate
- {
- [[self cancelledLock] lock];
- id d = delegate;
- [[self cancelledLock] unlock];
- return d;
- }
- - (void)setDelegate:(id)newDelegate
- {
- [[self cancelledLock] lock];
- delegate = newDelegate;
- [[self cancelledLock] unlock];
- }
- - (id)queue
- {
- [[self cancelledLock] lock];
- id q = queue;
- [[self cancelledLock] unlock];
- return q;
- }
- - (void)setQueue:(id)newQueue
- {
- [[self cancelledLock] lock];
- if (newQueue != queue) {
- [queue release];
- queue = [newQueue retain];
- }
- [[self cancelledLock] unlock];
- }
- #pragma mark get information about this request
- - (void)cancelOnRequestThread
- {
- #if DEBUG_REQUEST_STATUS
- ASI_DEBUG_LOG(@"[STATUS] Request cancelled: %@",self);
- #endif
-
- [[self cancelledLock] lock];
- if ([self isCancelled] || [self complete]) {
- [[self cancelledLock] unlock];
- return;
- }
- [self failWithError:ASIRequestCancelledError];
- [self setComplete:YES];
- [self cancelLoad];
-
- CFRetain(self);
- [self willChangeValueForKey:@"isCancelled"];
- cancelled = YES;
- [self didChangeValueForKey:@"isCancelled"];
-
- [[self cancelledLock] unlock];
- CFRelease(self);
- }
- - (void)cancel
- {
- [self performSelector:@selector(cancelOnRequestThread) onThread:[[self class] threadForRequest:self] withObject:nil waitUntilDone:NO];
- }
- - (void)clearDelegatesAndCancel
- {
- [[self cancelledLock] lock];
-
- [self setDelegate:nil];
- [self setQueue:nil];
- [self setDownloadProgressDelegate:nil];
- [self setUploadProgressDelegate:nil];
- #if NS_BLOCKS_AVAILABLE
-
- [self releaseBlocksOnMainThread];
- #endif
- [[self cancelledLock] unlock];
- [self cancel];
- }
- - (BOOL)isCancelled
- {
- BOOL result;
-
- [[self cancelledLock] lock];
- result = cancelled;
- [[self cancelledLock] unlock];
-
- return result;
- }
- - (NSString *)responseString
- {
- NSData *data = [self responseData];
- if (!data) {
- return nil;
- }
-
- return [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:[self responseEncoding]] autorelease];
- }
- - (BOOL)isResponseCompressed
- {
- NSString *encoding = [[self responseHeaders] objectForKey:@"Content-Encoding"];
- return encoding && [encoding rangeOfString:@"gzip"].location != NSNotFound;
- }
- - (NSData *)responseData
- {
- if ([self isResponseCompressed] && [self shouldWaitToInflateCompressedResponses]) {
- return [ASIDataDecompressor uncompressData:[self rawResponseData] error:NULL];
- } else {
- return [self rawResponseData];
- }
- return nil;
- }
- #pragma mark running a request
- - (void)startSynchronous
- {
- #if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
- ASI_DEBUG_LOG(@"[STATUS] Starting synchronous request %@",self);
- #endif
- [self setSynchronous:YES];
- [self setRunLoopMode:ASIHTTPRequestRunLoopMode];
- [self setInProgress:YES];
- if (![self isCancelled] && ![self complete]) {
- [self main];
- while (!complete) {
- [[NSRunLoop currentRunLoop] runMode:[self runLoopMode] beforeDate:[NSDate distantFuture]];
- }
- }
- [self setInProgress:NO];
- }
- - (void)start
- {
- [self setInProgress:YES];
- [self performSelector:@selector(main) onThread:[[self class] threadForRequest:self] withObject:nil waitUntilDone:NO];
- }
- - (void)startAsynchronous
- {
- #if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
- ASI_DEBUG_LOG(@"[STATUS] Starting asynchronous request %@",self);
- #endif
- [sharedQueue addOperation:self];
- }
- #pragma mark concurrency
- - (BOOL)isConcurrent
- {
- return YES;
- }
- - (BOOL)isFinished
- {
- return finished;
- }
- - (BOOL)isExecuting {
- return [self inProgress];
- }
- #pragma mark request logic
- - (void)main
- {
- @try {
-
- [[self cancelledLock] lock];
-
- #if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
- if ([ASIHTTPRequest isMultitaskingSupported] && [self shouldContinueWhenAppEntersBackground]) {
- if (!backgroundTask || backgroundTask == UIBackgroundTaskInvalid) {
- backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
-
-
- dispatch_async(dispatch_get_main_queue(), ^{
- if (backgroundTask != UIBackgroundTaskInvalid)
- {
- [[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
- backgroundTask = UIBackgroundTaskInvalid;
- [self cancel];
- }
- });
- }];
- }
- }
- #endif
-
- if ([self error]) {
- [self setComplete:YES];
- [self markAsFinished];
- return;
- }
- [self setComplete:NO];
- [self setDidUseCachedResponse:NO];
-
- if (![self url]) {
- [self failWithError:ASIUnableToCreateRequestError];
- return;
- }
-
-
- if (![self mainRequest]) {
- [self buildPostBody];
- }
-
- if (![[self requestMethod] isEqualToString:@"GET"]) {
- [self setDownloadCache:nil];
- }
-
-
-
- if (request) {
- CFRelease(request);
- }
-
- request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)[self requestMethod], (CFURLRef)[self url], [self useHTTPVersionOne] ? kCFHTTPVersion1_0 : kCFHTTPVersion1_1);
- if (!request) {
- [self failWithError:ASIUnableToCreateRequestError];
- return;
- }
-
- if ([self mainRequest]) {
- [[self mainRequest] buildRequestHeaders];
- }
-
-
- [self buildRequestHeaders];
-
- if ([self downloadCache]) {
-
- if (![self cachePolicy]) {
- [self setCachePolicy:[[self downloadCache] defaultCachePolicy]];
- }
-
- if ([[self downloadCache] canUseCachedDataForRequest:self]) {
- [self useDataFromCache];
- return;
- }
-
- if ([self cachePolicy] & (ASIAskServerIfModifiedWhenStaleCachePolicy|ASIAskServerIfModifiedCachePolicy)) {
- NSDictionary *cachedHeaders = [[self downloadCache] cachedResponseHeadersForURL:[self url]];
- if (cachedHeaders) {
- NSString *etag = [cachedHeaders objectForKey:@"Etag"];
- if (etag) {
- [[self requestHeaders] setObject:etag forKey:@"If-None-Match"];
- }
- NSString *lastModified = [cachedHeaders objectForKey:@"Last-Modified"];
- if (lastModified) {
- [[self requestHeaders] setObject:lastModified forKey:@"If-Modified-Since"];
- }
- }
- }
- }
- [self applyAuthorizationHeader];
-
-
- NSString *header;
- for (header in [self requestHeaders]) {
- CFHTTPMessageSetHeaderFieldValue(request, (CFStringRef)header, (CFStringRef)[[self requestHeaders] objectForKey:header]);
- }
-
-
- if ([self configureProxies]) {
- [self startRequest];
- }
- } @catch (NSException *exception) {
- NSError *underlyingError = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASIUnhandledExceptionError userInfo:[exception userInfo]];
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIUnhandledExceptionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[exception name],NSLocalizedDescriptionKey,[exception reason],NSLocalizedFailureReasonErrorKey,underlyingError,NSUnderlyingErrorKey,nil]]];
- } @finally {
- [[self cancelledLock] unlock];
- }
- }
- - (void)applyAuthorizationHeader
- {
-
- if (![self shouldPresentCredentialsBeforeChallenge]) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ will not send credentials to the server until it asks for them",self);
- #endif
- return;
- }
- NSDictionary *credentials = nil;
-
- if (![[self requestHeaders] objectForKey:@"Authorization"]) {
-
- if ([self username] && [self password] && [[self authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic]) {
- [self addBasicAuthenticationHeaderWithUsername:[self username] andPassword:[self password]];
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ has a username and password set, and was manually configured to use BASIC. Will send credentials without waiting for an authentication challenge",self);
- #endif
- } else {
-
- if ([self useSessionPersistence]) {
- credentials = [self findSessionAuthenticationCredentials];
- if (credentials) {
-
-
- if ([credentials objectForKey:@"Authentication"]) {
-
- if (CFHTTPMessageApplyCredentialDictionary(request, (CFHTTPAuthenticationRef)[credentials objectForKey:@"Authentication"], (CFDictionaryRef)[credentials objectForKey:@"Credentials"], NULL)) {
- [self setAuthenticationScheme:[credentials objectForKey:@"AuthenticationScheme"]];
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ found cached credentials (%@), will reuse without waiting for an authentication challenge",self,[credentials objectForKey:@"AuthenticationScheme"]);
- #endif
- } else {
- [[self class] removeAuthenticationCredentialsFromSessionStore:[credentials objectForKey:@"Credentials"]];
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Failed to apply cached credentials to request %@. These will be removed from the session store, and this request will wait for an authentication challenge",self);
- #endif
- }
-
-
- } else {
- NSDictionary *usernameAndPassword = [credentials objectForKey:@"Credentials"];
- [self addBasicAuthenticationHeaderWithUsername:[usernameAndPassword objectForKey:(NSString *)kCFHTTPAuthenticationUsername] andPassword:[usernameAndPassword objectForKey:(NSString *)kCFHTTPAuthenticationPassword]];
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ found cached BASIC credentials from a previous request. Will send credentials without waiting for an authentication challenge",self);
- #endif
- }
- }
- }
- }
- }
-
- if ([self useSessionPersistence]) {
- credentials = [self findSessionProxyAuthenticationCredentials];
- if (credentials) {
- if (!CFHTTPMessageApplyCredentialDictionary(request, (CFHTTPAuthenticationRef)[credentials objectForKey:@"Authentication"], (CFDictionaryRef)[credentials objectForKey:@"Credentials"], NULL)) {
- [[self class] removeProxyAuthenticationCredentialsFromSessionStore:[credentials objectForKey:@"Credentials"]];
- }
- }
- }
- }
- - (void)applyCookieHeader
- {
-
- if ([self useCookiePersistence]) {
- NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[[self url] absoluteURL]];
- if (cookies) {
- [[self requestCookies] addObjectsFromArray:cookies];
- }
- }
-
-
- NSArray *cookies;
- if ([self mainRequest]) {
- cookies = [[self mainRequest] requestCookies];
- } else {
- cookies = [self requestCookies];
- }
- if ([cookies count] > 0) {
- NSHTTPCookie *cookie;
- NSString *cookieHeader = nil;
- for (cookie in cookies) {
- if (!cookieHeader) {
- cookieHeader = [NSString stringWithFormat: @"%@=%@",[cookie name],[cookie value]];
- } else {
- cookieHeader = [NSString stringWithFormat: @"%@; %@=%@",cookieHeader,[cookie name],[cookie value]];
- }
- }
- if (cookieHeader) {
- [self addRequestHeader:@"Cookie" value:cookieHeader];
- }
- }
- }
- - (void)buildRequestHeaders
- {
- if ([self haveBuiltRequestHeaders]) {
- return;
- }
- [self setHaveBuiltRequestHeaders:YES];
-
- if ([self mainRequest]) {
- for (NSString *header in [[self mainRequest] requestHeaders]) {
- [self addRequestHeader:header value:[[[self mainRequest] requestHeaders] valueForKey:header]];
- }
- return;
- }
-
- [self applyCookieHeader];
-
-
- if (![[self requestHeaders] objectForKey:@"User-Agent"]) {
- NSString *tempUserAgentString = [self userAgentString];
- if (!tempUserAgentString) {
- tempUserAgentString = [ASIHTTPRequest defaultUserAgentString];
- }
- if (tempUserAgentString) {
- [self addRequestHeader:@"User-Agent" value:tempUserAgentString];
- }
- }
-
-
-
- if ([self allowCompressedResponse]) {
- [self addRequestHeader:@"Accept-Encoding" value:@"gzip"];
- }
-
-
- if ([self shouldCompressRequestBody]) {
- [self addRequestHeader:@"Content-Encoding" value:@"gzip"];
- }
-
-
- [self updatePartialDownloadSize];
- if ([self partialDownloadSize]) {
- [self addRequestHeader:@"Range" value:[NSString stringWithFormat:@"bytes=%llu-",[self partialDownloadSize]]];
- }
- }
- - (void)updatePartialDownloadSize
- {
- NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
- if ([self allowResumeForFileDownloads] && [self downloadDestinationPath] && [self temporaryFileDownloadPath] && [fileManager fileExistsAtPath:[self temporaryFileDownloadPath]]) {
- NSError *err = nil;
- [self setPartialDownloadSize:[[fileManager attributesOfItemAtPath:[self temporaryFileDownloadPath] error:&err] fileSize]];
- if (err) {
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIFileManagementError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Failed to get attributes for file at path '%@'",[self temporaryFileDownloadPath]],NSLocalizedDescriptionKey,error,NSUnderlyingErrorKey,nil]]];
- return;
- }
- }
- }
- - (void)startRequest
- {
- if ([self isCancelled]) {
- return;
- }
-
- [self performSelectorOnMainThread:@selector(requestStarted) withObject:nil waitUntilDone:[NSThread isMainThread]];
-
- [self setDownloadComplete:NO];
- [self setComplete:NO];
- [self setTotalBytesRead:0];
- [self setLastBytesRead:0];
-
- if ([self redirectCount] == 0) {
- [self setOriginalURL:[self url]];
- }
-
-
- if ([self lastBytesSent] > 0) {
- [self removeUploadProgressSoFar];
- }
-
- [self setLastBytesSent:0];
- [self setContentLength:0];
- [self setResponseHeaders:nil];
- if (![self downloadDestinationPath]) {
- [self setRawResponseData:[[[NSMutableData alloc] init] autorelease]];
- }
-
-
-
-
-
- NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
- [self setReadStreamIsScheduled:NO];
-
-
- if ([self shouldStreamPostDataFromDisk] && [self postBodyFilePath] && [fileManager fileExistsAtPath:[self postBodyFilePath]]) {
-
-
- if ([self compressedPostBodyFilePath] && [fileManager fileExistsAtPath:[self compressedPostBodyFilePath]]) {
- [self setPostBodyReadStream:[ASIInputStream inputStreamWithFileAtPath:[self compressedPostBodyFilePath] request:self]];
- } else {
- [self setPostBodyReadStream:[ASIInputStream inputStreamWithFileAtPath:[self postBodyFilePath] request:self]];
- }
- [self setReadStream:[NSMakeCollectable(CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,(CFReadStreamRef)[self postBodyReadStream])) autorelease]];
- } else {
-
-
- if ([self postBody] && [[self postBody] length] > 0) {
- if ([self shouldCompressRequestBody] && [self compressedPostBody]) {
- [self setPostBodyReadStream:[ASIInputStream inputStreamWithData:[self compressedPostBody] request:self]];
- } else if ([self postBody]) {
- [self setPostBodyReadStream:[ASIInputStream inputStreamWithData:[self postBody] request:self]];
- }
- [self setReadStream:[NSMakeCollectable(CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,(CFReadStreamRef)[self postBodyReadStream])) autorelease]];
-
- } else {
- [self setReadStream:[NSMakeCollectable(CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request)) autorelease]];
- }
- }
- if (![self readStream]) {
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to create read stream",NSLocalizedDescriptionKey,nil]]];
- return;
- }
-
-
-
-
-
- if([[[[self url] scheme] lowercaseString] isEqualToString:@"https"]) {
-
-
- if (![self validatesSecureCertificate]) {
-
-
- NSDictionary *sslProperties = [[NSDictionary alloc] initWithObjectsAndKeys:
- [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
- [NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
- [NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
- kCFNull,kCFStreamSSLPeerName,
- nil];
-
- CFReadStreamSetProperty((CFReadStreamRef)[self readStream],
- kCFStreamPropertySSLSettings,
- (CFTypeRef)sslProperties);
- [sslProperties release];
- }
-
-
- if (clientCertificateIdentity) {
- NSMutableDictionary *sslProperties = [NSMutableDictionary dictionaryWithCapacity:1];
-
- NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[clientCertificates count]+1];
-
- [certificates addObject:(id)clientCertificateIdentity];
-
- for (id cert in clientCertificates) {
- [certificates addObject:cert];
- }
-
- [sslProperties setObject:certificates forKey:(NSString *)kCFStreamSSLCertificates];
-
- CFReadStreamSetProperty((CFReadStreamRef)[self readStream], kCFStreamPropertySSLSettings, sslProperties);
- }
-
- }
-
-
-
- if ([self proxyHost] && [self proxyPort]) {
- NSString *hostKey;
- NSString *portKey;
- if (![self proxyType]) {
- [self setProxyType:(NSString *)kCFProxyTypeHTTP];
- }
- if ([[self proxyType] isEqualToString:(NSString *)kCFProxyTypeSOCKS]) {
- hostKey = (NSString *)kCFStreamPropertySOCKSProxyHost;
- portKey = (NSString *)kCFStreamPropertySOCKSProxyPort;
- } else {
- hostKey = (NSString *)kCFStreamPropertyHTTPProxyHost;
- portKey = (NSString *)kCFStreamPropertyHTTPProxyPort;
- if ([[[[self url] scheme] lowercaseString] isEqualToString:@"https"]) {
- hostKey = (NSString *)kCFStreamPropertyHTTPSProxyHost;
- portKey = (NSString *)kCFStreamPropertyHTTPSProxyPort;
- }
- }
- NSMutableDictionary *proxyToUse = [NSMutableDictionary dictionaryWithObjectsAndKeys:[self proxyHost],hostKey,[NSNumber numberWithInt:[self proxyPort]],portKey,nil];
- if ([[self proxyType] isEqualToString:(NSString *)kCFProxyTypeSOCKS]) {
- CFReadStreamSetProperty((CFReadStreamRef)[self readStream], kCFStreamPropertySOCKSProxy, proxyToUse);
- } else {
- CFReadStreamSetProperty((CFReadStreamRef)[self readStream], kCFStreamPropertyHTTPProxy, proxyToUse);
- }
- }
-
-
-
-
- [ASIHTTPRequest expirePersistentConnections];
- [connectionsLock lock];
-
-
- if (![[self url] host] || ![[self url] scheme]) {
- [self setConnectionInfo:nil];
- [self setShouldAttemptPersistentConnection:NO];
- }
-
-
- NSInputStream *oldStream = nil;
-
-
- if ([self shouldAttemptPersistentConnection]) {
-
-
- if ([self connectionInfo]) {
-
- if (![[[self connectionInfo] objectForKey:@"host"] isEqualToString:[[self url] host]] || ![[[self connectionInfo] objectForKey:@"scheme"] isEqualToString:[[self url] scheme]] || [(NSNumber *)[[self connectionInfo] objectForKey:@"port"] intValue] != [[[self url] port] intValue]) {
- [self setConnectionInfo:nil];
-
- } else if ([[[self connectionInfo] objectForKey:@"expires"] timeIntervalSinceNow] < 0) {
- #if DEBUG_PERSISTENT_CONNECTIONS
- ASI_DEBUG_LOG(@"[CONNECTION] Not re-using connection #%i because it has expired",[[[self connectionInfo] objectForKey:@"id"] intValue]);
- #endif
- [persistentConnectionsPool removeObject:[self connectionInfo]];
- [self setConnectionInfo:nil];
- } else if ([[self connectionInfo] objectForKey:@"request"] != nil) {
-
- #if DEBUG_PERSISTENT_CONNECTIONS
- ASI_DEBUG_LOG(@"%@ - Not re-using connection #%i for request #%i because it is already used by request #%i",self,[[[self connectionInfo] objectForKey:@"id"] intValue],[[self requestID] intValue],[[[self connectionInfo] objectForKey:@"request"] intValue]);
- #endif
- [self setConnectionInfo:nil];
- }
- }
-
-
-
- if (![self connectionInfo] && [[self url] host] && [[self url] scheme]) {
-
-
- for (NSMutableDictionary *existingConnection in persistentConnectionsPool) {
- if (![existingConnection objectForKey:@"request"] && [[existingConnection objectForKey:@"host"] isEqualToString:[[self url] host]] && [[existingConnection objectForKey:@"scheme"] isEqualToString:[[self url] scheme]] && [(NSNumber *)[existingConnection objectForKey:@"port"] intValue] == [[[self url] port] intValue]) {
- [self setConnectionInfo:existingConnection];
- }
- }
- }
-
- if ([[self connectionInfo] objectForKey:@"stream"]) {
- oldStream = [[[self connectionInfo] objectForKey:@"stream"] retain];
- }
-
-
- if (![self connectionInfo]) {
- [self setConnectionInfo:[NSMutableDictionary dictionary]];
- nextConnectionNumberToCreate++;
- [[self connectionInfo] setObject:[NSNumber numberWithInt:(int)nextConnectionNumberToCreate] forKey:@"id"];
- [[self connectionInfo] setObject:[[self url] host] forKey:@"host"];
- [[self connectionInfo] setObject:[NSNumber numberWithInt:[[[self url] port] intValue]] forKey:@"port"];
- [[self connectionInfo] setObject:[[self url] scheme] forKey:@"scheme"];
- [persistentConnectionsPool addObject:[self connectionInfo]];
- }
-
-
- if (![self requestID]) {
- nextRequestID++;
- [self setRequestID:[NSNumber numberWithUnsignedInt:nextRequestID]];
- }
- [[self connectionInfo] setObject:[self requestID] forKey:@"request"];
- [[self connectionInfo] setObject:[self readStream] forKey:@"stream"];
- CFReadStreamSetProperty((CFReadStreamRef)[self readStream], kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue);
-
- #if DEBUG_PERSISTENT_CONNECTIONS
- ASI_DEBUG_LOG(@"[CONNECTION] Request #%@ will use connection #%i",[self requestID],[[[self connectionInfo] objectForKey:@"id"] intValue]);
- #endif
-
-
-
-
-
- CFReadStreamSetProperty((CFReadStreamRef)[self readStream], CFSTR("ASIStreamID"), [[self connectionInfo] objectForKey:@"id"]);
-
- } else {
- #if DEBUG_PERSISTENT_CONNECTIONS
- ASI_DEBUG_LOG(@"[CONNECTION] Request %@ will not use a persistent connection",self);
- #endif
- }
-
- [connectionsLock unlock];
-
- if (![self readStreamIsScheduled] && (!throttleWakeUpTime || [throttleWakeUpTime timeIntervalSinceDate:[NSDate date]] < 0)) {
- [self scheduleReadStream];
- }
-
- BOOL streamSuccessfullyOpened = NO;
-
- CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL};
- if (CFReadStreamSetClient((CFReadStreamRef)[self readStream], kNetworkEvents, ReadStreamClientCallBack, &ctxt)) {
- if (CFReadStreamOpen((CFReadStreamRef)[self readStream])) {
- streamSuccessfullyOpened = YES;
- }
- }
-
-
-
-
- if (oldStream) {
- [oldStream close];
- [oldStream release];
- oldStream = nil;
- }
- if (!streamSuccessfullyOpened) {
- [self setConnectionCanBeReused:NO];
- [self destroyReadStream];
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to start HTTP connection",NSLocalizedDescriptionKey,nil]]];
- return;
- }
-
- if (![self mainRequest]) {
- if ([self shouldResetUploadProgress]) {
- if ([self showAccurateProgress]) {
- [self incrementUploadSizeBy:(long long)[self postLength]];
- } else {
- [self incrementUploadSizeBy:1];
- }
- [ASIHTTPRequest updateProgressIndicator:&uploadProgressDelegate withProgress:0 ofTotal:1];
- }
- if ([self shouldResetDownloadProgress] && ![self partialDownloadSize]) {
- [ASIHTTPRequest updateProgressIndicator:&downloadProgressDelegate withProgress:0 ofTotal:1];
- }
- }
-
-
-
- [self setLastActivityTime:[NSDate date]];
- [self setStatusTimer:[NSTimer timerWithTimeInterval:0.25 target:self selector:@selector(updateStatus:) userInfo:nil repeats:YES]];
- [[NSRunLoop currentRunLoop] addTimer:[self statusTimer] forMode:[self runLoopMode]];
- }
- - (void)setStatusTimer:(NSTimer *)timer
- {
- CFRetain(self);
-
-
- if (statusTimer && timer != statusTimer) {
- [statusTimer invalidate];
- [statusTimer release];
- }
- statusTimer = [timer retain];
- CFRelease(self);
- }
- - (void)updateStatus:(NSTimer*)timer
- {
- [self checkRequestStatus];
- if (![self inProgress]) {
- [self setStatusTimer:nil];
- }
- }
- - (void)performRedirect
- {
- [self setURL:[self redirectURL]];
- [self setComplete:YES];
- [self setNeedsRedirect:NO];
- [self setRedirectCount:[self redirectCount]+1];
- if ([self redirectCount] > RedirectionLimit) {
-
- [self failWithError:ASITooMuchRedirectionError];
- [self setComplete:YES];
- } else {
-
- [self main];
- }
- }
- - (void)redirectToURL:(NSURL *)newURL
- {
- [self setRedirectURL:newURL];
- [self performSelector:@selector(performRedirect) onThread:[[self class] threadForRequest:self] withObject:nil waitUntilDone:NO];
- }
- - (BOOL)shouldTimeOut
- {
- NSTimeInterval secondsSinceLastActivity = [[NSDate date] timeIntervalSinceDate:lastActivityTime];
-
- if ([self readStream] && [self readStreamIsScheduled] && [self lastActivityTime] && [self timeOutSeconds] > 0 && secondsSinceLastActivity > [self timeOutSeconds]) {
-
-
- if ([self postLength] == 0 || ([self uploadBufferSize] > 0 && [self totalBytesSent] > [self uploadBufferSize])) {
- return YES;
-
-
-
-
- } else if (secondsSinceLastActivity > [self timeOutSeconds]*1.5) {
- return YES;
- }
- }
- return NO;
- }
- - (void)checkRequestStatus
- {
-
- [[self cancelledLock] lock];
-
- if ([self isCancelled] || [self complete]) {
- [[self cancelledLock] unlock];
- return;
- }
-
- [self performThrottling];
-
- if ([self shouldTimeOut]) {
-
- if ([self numberOfTimesToRetryOnTimeout] > [self retryCount]) {
-
- [self updatePartialDownloadSize];
- if ([self partialDownloadSize]) {
- CFHTTPMessageSetHeaderFieldValue(request, (CFStringRef)@"Range", (CFStringRef)[NSString stringWithFormat:@"bytes=%llu-",[self partialDownloadSize]]);
- }
- [self setRetryCount:[self retryCount]+1];
- [self unscheduleReadStream];
- [[self cancelledLock] unlock];
- [self startRequest];
- return;
- }
- [self failWithError:ASIRequestTimedOutError];
- [self cancelLoad];
- [self setComplete:YES];
- [[self cancelledLock] unlock];
- return;
- }
-
- if ([self readStream]) {
-
-
- if ([self postLength]) {
-
- [self setLastBytesSent:totalBytesSent];
-
-
- [self setTotalBytesSent:[[NSMakeCollectable(CFReadStreamCopyProperty((CFReadStreamRef)[self readStream], kCFStreamPropertyHTTPRequestBytesWrittenCount)) autorelease] unsignedLongLongValue]];
- if (totalBytesSent > lastBytesSent) {
-
-
- [self setLastActivityTime:[NSDate date]];
- [ASIHTTPRequest incrementBandwidthUsedInLastSecond:(unsigned long)(totalBytesSent-lastBytesSent)];
-
- #if DEBUG_REQUEST_STATUS
- if ([self totalBytesSent] == [self postLength]) {
- ASI_DEBUG_LOG(@"[STATUS] Request %@ finished uploading data",self);
- }
- #endif
- }
- }
-
- [self updateProgressIndicators];
- }
-
- [[self cancelledLock] unlock];
- }
- - (void)cancelLoad
- {
-
- if (PACFileReadStream) {
- [PACFileReadStream setDelegate:nil];
- [PACFileReadStream close];
- [self setPACFileReadStream:nil];
- [self setPACFileData:nil];
- } else if (PACFileRequest) {
- [PACFileRequest setDelegate:nil];
- [PACFileRequest cancel];
- [self setPACFileRequest:nil];
- }
- [self destroyReadStream];
-
- [[self postBodyReadStream] close];
- [self setPostBodyReadStream:nil];
-
- if ([self rawResponseData]) {
- if (![self complete]) {
- [self setRawResponseData:nil];
- }
-
- } else if ([self temporaryFileDownloadPath]) {
- [[self fileDownloadOutputStream] close];
- [self setFileDownloadOutputStream:nil];
-
- [[self inflatedFileDownloadOutputStream] close];
- [self setInflatedFileDownloadOutputStream:nil];
-
-
- if (![self complete]) {
- if (![self allowResumeForFileDownloads]) {
- [self removeTemporaryDownloadFile];
- }
- [self removeTemporaryUncompressedDownloadFile];
- }
- }
-
-
- if (![self authenticationNeeded] && ![self willRetryRequest] && [self didCreateTemporaryPostDataFile]) {
- [self removeTemporaryUploadFile];
- [self removeTemporaryCompressedUploadFile];
- [self setDidCreateTemporaryPostDataFile:NO];
- }
- }
- #pragma mark HEAD request
- - (ASIHTTPRequest *)HEADRequest
- {
- ASIHTTPRequest *headRequest = [[self class] requestWithURL:[self url]];
-
-
- [headRequest setRequestHeaders:[[[self requestHeaders] mutableCopy] autorelease]];
- [headRequest setRequestCookies:[[[self requestCookies] mutableCopy] autorelease]];
- [headRequest setUseCookiePersistence:[self useCookiePersistence]];
- [headRequest setUseKeychainPersistence:[self useKeychainPersistence]];
- [headRequest setUseSessionPersistence:[self useSessionPersistence]];
- [headRequest setAllowCompressedResponse:[self allowCompressedResponse]];
- [headRequest setUsername:[self username]];
- [headRequest setPassword:[self password]];
- [headRequest setDomain:[self domain]];
- [headRequest setProxyUsername:[self proxyUsername]];
- [headRequest setProxyPassword:[self proxyPassword]];
- [headRequest setProxyDomain:[self proxyDomain]];
- [headRequest setProxyHost:[self proxyHost]];
- [headRequest setProxyPort:[self proxyPort]];
- [headRequest setProxyType:[self proxyType]];
- [headRequest setShouldPresentAuthenticationDialog:[self shouldPresentAuthenticationDialog]];
- [headRequest setShouldPresentProxyAuthenticationDialog:[self shouldPresentProxyAuthenticationDialog]];
- [headRequest setTimeOutSeconds:[self timeOutSeconds]];
- [headRequest setUseHTTPVersionOne:[self useHTTPVersionOne]];
- [headRequest setValidatesSecureCertificate:[self validatesSecureCertificate]];
- [headRequest setClientCertificateIdentity:clientCertificateIdentity];
- [headRequest setClientCertificates:[[clientCertificates copy] autorelease]];
- [headRequest setPACurl:[self PACurl]];
- [headRequest setShouldPresentCredentialsBeforeChallenge:[self shouldPresentCredentialsBeforeChallenge]];
- [headRequest setNumberOfTimesToRetryOnTimeout:[self numberOfTimesToRetryOnTimeout]];
- [headRequest setShouldUseRFC2616RedirectBehaviour:[self shouldUseRFC2616RedirectBehaviour]];
- [headRequest setShouldAttemptPersistentConnection:[self shouldAttemptPersistentConnection]];
- [headRequest setPersistentConnectionTimeoutSeconds:[self persistentConnectionTimeoutSeconds]];
-
- [headRequest setMainRequest:self];
- [headRequest setRequestMethod:@"HEAD"];
- return headRequest;
- }
- #pragma mark upload/download progress
- - (void)updateProgressIndicators
- {
-
- if (![self mainRequest]) {
- if ([self showAccurateProgress] || ([self complete] && ![self updatedProgress])) {
- [self updateUploadProgress];
- [self updateDownloadProgress];
- }
- }
- }
- - (id)uploadProgressDelegate
- {
- [[self cancelledLock] lock];
- id d = [[uploadProgressDelegate retain] autorelease];
- [[self cancelledLock] unlock];
- return d;
- }
- - (void)setUploadProgressDelegate:(id)newDelegate
- {
- [[self cancelledLock] lock];
- uploadProgressDelegate = newDelegate;
- #if !TARGET_OS_IPHONE
-
- double max = 1.0;
- [ASIHTTPRequest performSelector:@selector(setMaxValue:) onTarget:&uploadProgressDelegate withObject:nil amount:&max callerToRetain:nil];
- #endif
- [[self cancelledLock] unlock];
- }
- - (id)downloadProgressDelegate
- {
- [[self cancelledLock] lock];
- id d = [[downloadProgressDelegate retain] autorelease];
- [[self cancelledLock] unlock];
- return d;
- }
- - (void)setDownloadProgressDelegate:(id)newDelegate
- {
- [[self cancelledLock] lock];
- downloadProgressDelegate = newDelegate;
- #if !TARGET_OS_IPHONE
-
- double max = 1.0;
- [ASIHTTPRequest performSelector:@selector(setMaxValue:) onTarget:&downloadProgressDelegate withObject:nil amount:&max callerToRetain:nil];
- #endif
- [[self cancelledLock] unlock];
- }
- - (void)updateDownloadProgress
- {
-
- if (![self responseHeaders] || [self needsRedirect] || !([self contentLength] || [self complete])) {
- return;
- }
-
- unsigned long long bytesReadSoFar = [self totalBytesRead]+[self partialDownloadSize];
- unsigned long long value = 0;
-
- if ([self showAccurateProgress] && [self contentLength]) {
- value = bytesReadSoFar-[self lastBytesRead];
- if (value == 0) {
- return;
- }
- } else {
- value = 1;
- [self setUpdatedProgress:YES];
- }
- if (!value) {
- return;
- }
- [ASIHTTPRequest performSelector:@selector(request:didReceiveBytes:) onTarget:&queue withObject:self amount:&value callerToRetain:self];
- [ASIHTTPRequest performSelector:@selector(request:didReceiveBytes:) onTarget:&downloadProgressDelegate withObject:self amount:&value callerToRetain:self];
- [ASIHTTPRequest updateProgressIndicator:&downloadProgressDelegate withProgress:[self totalBytesRead]+[self partialDownloadSize] ofTotal:[self contentLength]+[self partialDownloadSize]];
- #if NS_BLOCKS_AVAILABLE
- if (bytesReceivedBlock) {
- unsigned long long totalSize = [self contentLength] + [self partialDownloadSize];
- [self performBlockOnMainThread:^{ if (bytesReceivedBlock) { bytesReceivedBlock(value, totalSize); }}];
- }
- #endif
- [self setLastBytesRead:bytesReadSoFar];
- }
- - (void)updateUploadProgress
- {
- if ([self isCancelled] || [self totalBytesSent] == 0) {
- return;
- }
-
-
-
-
- if ([self uploadBufferSize] == 0 && [self totalBytesSent] != [self postLength]) {
- [self setUploadBufferSize:[self totalBytesSent]];
- [self incrementUploadSizeBy:-(long long)[self uploadBufferSize]];
- }
-
- unsigned long long value = 0;
-
- if ([self showAccurateProgress]) {
- if ([self totalBytesSent] == [self postLength] || [self lastBytesSent] > 0) {
- value = [self totalBytesSent]-[self lastBytesSent];
- } else {
- return;
- }
- } else {
- value = 1;
- [self setUpdatedProgress:YES];
- }
-
- if (!value) {
- return;
- }
-
- [ASIHTTPRequest performSelector:@selector(request:didSendBytes:) onTarget:&queue withObject:self amount:&value callerToRetain:self];
- [ASIHTTPRequest performSelector:@selector(request:didSendBytes:) onTarget:&uploadProgressDelegate withObject:self amount:&value callerToRetain:self];
- [ASIHTTPRequest updateProgressIndicator:&uploadProgressDelegate withProgress:[self totalBytesSent]-[self uploadBufferSize] ofTotal:[self postLength]-[self uploadBufferSize]];
- #if NS_BLOCKS_AVAILABLE
- if(bytesSentBlock){
- unsigned long long totalSize = [self postLength];
- [self performBlockOnMainThread:^{ if (bytesSentBlock) { bytesSentBlock(value, totalSize); }}];
- }
- #endif
- }
- - (void)incrementDownloadSizeBy:(long long)length
- {
- [ASIHTTPRequest performSelector:@selector(request:incrementDownloadSizeBy:) onTarget:&queue withObject:self amount:&length callerToRetain:self];
- [ASIHTTPRequest performSelector:@selector(request:incrementDownloadSizeBy:) onTarget:&downloadProgressDelegate withObject:self amount:&length callerToRetain:self];
- #if NS_BLOCKS_AVAILABLE
- if(downloadSizeIncrementedBlock){
- [self performBlockOnMainThread:^{ if (downloadSizeIncrementedBlock) { downloadSizeIncrementedBlock(length); }}];
- }
- #endif
- }
- - (void)incrementUploadSizeBy:(long long)length
- {
- [ASIHTTPRequest performSelector:@selector(request:incrementUploadSizeBy:) onTarget:&queue withObject:self amount:&length callerToRetain:self];
- [ASIHTTPRequest performSelector:@selector(request:incrementUploadSizeBy:) onTarget:&uploadProgressDelegate withObject:self amount:&length callerToRetain:self];
- #if NS_BLOCKS_AVAILABLE
- if(uploadSizeIncrementedBlock) {
- [self performBlockOnMainThread:^{ if (uploadSizeIncrementedBlock) { uploadSizeIncrementedBlock(length); }}];
- }
- #endif
- }
- -(void)removeUploadProgressSoFar
- {
- long long progressToRemove = -(long long)[self totalBytesSent];
- [ASIHTTPRequest performSelector:@selector(request:didSendBytes:) onTarget:&queue withObject:self amount:&progressToRemove callerToRetain:self];
- [ASIHTTPRequest performSelector:@selector(request:didSendBytes:) onTarget:&uploadProgressDelegate withObject:self amount:&progressToRemove callerToRetain:self];
- [ASIHTTPRequest updateProgressIndicator:&uploadProgressDelegate withProgress:0 ofTotal:[self postLength]];
- #if NS_BLOCKS_AVAILABLE
- if(bytesSentBlock){
- unsigned long long totalSize = [self postLength];
- [self performBlockOnMainThread:^{ if (bytesSentBlock) { bytesSentBlock((unsigned long long)progressToRemove, totalSize); }}];
- }
- #endif
- }
- #if NS_BLOCKS_AVAILABLE
- - (void)performBlockOnMainThread:(ASIBasicBlock)block
- {
- [self performSelectorOnMainThread:@selector(callBlock:) withObject:[[block copy] autorelease] waitUntilDone:[NSThread isMainThread]];
- }
- - (void)callBlock:(ASIBasicBlock)block
- {
- block();
- }
- #endif
- + (void)performSelector:(SEL)selector onTarget:(id *)target withObject:(id)object amount:(void *)amount callerToRetain:(id)callerToRetain
- {
- if ([*target respondsToSelector:selector]) {
- NSMethodSignature *signature = nil;
- signature = [*target methodSignatureForSelector:selector];
- NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
- [invocation setSelector:selector];
-
- int argumentNumber = 2;
-
-
- if (object) {
- [invocation setArgument:&object atIndex:argumentNumber];
- argumentNumber++;
- }
-
-
- if (amount) {
- [invocation setArgument:amount atIndex:argumentNumber];
- }
- SEL callback = @selector(performInvocation:onTarget:releasingObject:);
- NSMethodSignature *cbSignature = [ASIHTTPRequest methodSignatureForSelector:callback];
- NSInvocation *cbInvocation = [NSInvocation invocationWithMethodSignature:cbSignature];
- [cbInvocation setSelector:callback];
- [cbInvocation setTarget:self];
- [cbInvocation setArgument:&invocation atIndex:2];
- [cbInvocation setArgument:&target atIndex:3];
- if (callerToRetain) {
- [cbInvocation setArgument:&callerToRetain atIndex:4];
- }
- CFRetain(invocation);
-
-
- if (callerToRetain) {
- CFRetain(callerToRetain);
- }
- [cbInvocation performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:[NSThread isMainThread]];
- }
- }
- + (void)performInvocation:(NSInvocation *)invocation onTarget:(id *)target releasingObject:(id)objectToRelease
- {
- if (*target && [*target respondsToSelector:[invocation selector]]) {
- [invocation invokeWithTarget:*target];
- }
- CFRelease(invocation);
- if (objectToRelease) {
- CFRelease(objectToRelease);
- }
- }
-
-
- + (void)updateProgressIndicator:(id *)indicator withProgress:(unsigned long long)progress ofTotal:(unsigned long long)total
- {
- #if TARGET_OS_IPHONE
-
- SEL selector = @selector(setProgress:);
- float progressAmount = (float)((progress*1.0)/(total*1.0));
-
- #else
-
- double progressAmount = progressAmount = (progress*1.0)/(total*1.0);
- SEL selector = @selector(setDoubleValue:);
- #endif
-
- if (![*indicator respondsToSelector:selector]) {
- return;
- }
-
- [progressLock lock];
- [ASIHTTPRequest performSelector:selector onTarget:indicator withObject:nil amount:&progressAmount callerToRetain:nil];
- [progressLock unlock];
- }
- #pragma mark talking to delegates / calling blocks
- - (void)requestStarted
- {
- if ([self error] || [self mainRequest]) {
- return;
- }
- if (delegate && [delegate respondsToSelector:didStartSelector]) {
- [delegate performSelector:didStartSelector withObject:self];
- }
- #if NS_BLOCKS_AVAILABLE
- if(startedBlock){
- startedBlock();
- }
- #endif
- if (queue && [queue respondsToSelector:@selector(requestStarted:)]) {
- [queue performSelector:@selector(requestStarted:) withObject:self];
- }
- }
- - (void)requestRedirected
- {
- if ([self error] || [self mainRequest]) {
- return;
- }
- if([[self delegate] respondsToSelector:@selector(requestRedirected:)]){
- [[self delegate] performSelector:@selector(requestRedirected:) withObject:self];
- }
- #if NS_BLOCKS_AVAILABLE
- if(requestRedirectedBlock){
- requestRedirectedBlock();
- }
- #endif
- }
- - (void)requestReceivedResponseHeaders:(NSMutableDictionary *)newResponseHeaders
- {
- if ([self error] || [self mainRequest]) {
- return;
- }
- if (delegate && [delegate respondsToSelector:didReceiveResponseHeadersSelector]) {
- [delegate performSelector:didReceiveResponseHeadersSelector withObject:self withObject:newResponseHeaders];
- }
- #if NS_BLOCKS_AVAILABLE
- if(headersReceivedBlock){
- headersReceivedBlock(newResponseHeaders);
- }
- #endif
- if (queue && [queue respondsToSelector:@selector(request:didReceiveResponseHeaders:)]) {
- [queue performSelector:@selector(request:didReceiveResponseHeaders:) withObject:self withObject:newResponseHeaders];
- }
- }
- - (void)requestWillRedirectToURL:(NSURL *)newURL
- {
- if ([self error] || [self mainRequest]) {
- return;
- }
- if (delegate && [delegate respondsToSelector:willRedirectSelector]) {
- [delegate performSelector:willRedirectSelector withObject:self withObject:newURL];
- }
- if (queue && [queue respondsToSelector:@selector(request:willRedirectToURL:)]) {
- [queue performSelector:@selector(request:willRedirectToURL:) withObject:self withObject:newURL];
- }
- }
- - (void)requestFinished
- {
- #if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
- ASI_DEBUG_LOG(@"[STATUS] Request finished: %@",self);
- #endif
- if ([self error] || [self mainRequest]) {
- return;
- }
- if ([self isPACFileRequest]) {
- [self reportFinished];
- } else {
- [self performSelectorOnMainThread:@selector(reportFinished) withObject:nil waitUntilDone:[NSThread isMainThread]];
- }
- }
- - (void)reportFinished
- {
- if (delegate && [delegate respondsToSelector:didFinishSelector]) {
- [delegate performSelector:didFinishSelector withObject:self];
- }
- #if NS_BLOCKS_AVAILABLE
- if(completionBlock){
- completionBlock();
- }
- #endif
- if (queue && [queue respondsToSelector:@selector(requestFinished:)]) {
- [queue performSelector:@selector(requestFinished:) withObject:self];
- }
- }
- - (void)reportFailure
- {
- if (delegate && [delegate respondsToSelector:didFailSelector]) {
- [delegate performSelector:didFailSelector withObject:self];
- }
- #if NS_BLOCKS_AVAILABLE
- if(failureBlock){
- failureBlock();
- }
- #endif
- if (queue && [queue respondsToSelector:@selector(requestFailed:)]) {
- [queue performSelector:@selector(requestFailed:) withObject:self];
- }
- }
- - (void)passOnReceivedData:(NSData *)data
- {
- if (delegate && [delegate respondsToSelector:didReceiveDataSelector]) {
- [delegate performSelector:didReceiveDataSelector withObject:self withObject:data];
- }
- #if NS_BLOCKS_AVAILABLE
- if (dataReceivedBlock) {
- dataReceivedBlock(data);
- }
- #endif
- }
- - (void)failWithError:(NSError *)theError
- {
- #if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
- ASI_DEBUG_LOG(@"[STATUS] Request %@: %@",self,(theError == ASIRequestCancelledError ? @"Cancelled" : @"Failed"));
- #endif
- [self setComplete:YES];
-
-
- if (theError && [theError code] != ASIAuthenticationErrorType && [theError code] != ASITooMuchRedirectionErrorType) {
- [connectionsLock lock];
- #if DEBUG_PERSISTENT_CONNECTIONS
- ASI_DEBUG_LOG(@"[CONNECTION] Request #%@ failed and will invalidate connection #%@",[self requestID],[[self connectionInfo] objectForKey:@"id"]);
- #endif
- [[self connectionInfo] removeObjectForKey:@"request"];
- [persistentConnectionsPool removeObject:[self connectionInfo]];
- [connectionsLock unlock];
- [self destroyReadStream];
- }
- if ([self connectionCanBeReused]) {
- [[self connectionInfo] setObject:[NSDate dateWithTimeIntervalSinceNow:[self persistentConnectionTimeoutSeconds]] forKey:@"expires"];
- }
-
- if ([self isCancelled] || [self error]) {
- return;
- }
-
-
- if ([self downloadCache] && ([self cachePolicy] & ASIFallbackToCacheIfLoadFailsCachePolicy)) {
- if ([[self downloadCache] canUseCachedDataForRequest:self]) {
- [self useDataFromCache];
- return;
- }
- }
-
-
- [self setError:theError];
-
- ASIHTTPRequest *failedRequest = self;
-
-
- if ([self mainRequest]) {
- failedRequest = [self mainRequest];
- [failedRequest setError:theError];
- }
- if ([self isPACFileRequest]) {
- [failedRequest reportFailure];
- } else {
- [failedRequest performSelectorOnMainThread:@selector(reportFailure) withObject:nil waitUntilDone:[NSThread isMainThread]];
- }
-
- if (!inProgress)
- {
-
-
- return;
- }
- [self markAsFinished];
- }
- #pragma mark parsing HTTP response headers
- - (void)readResponseHeaders
- {
- [self setAuthenticationNeeded:ASINoAuthenticationNeededYet];
- CFHTTPMessageRef message = (CFHTTPMessageRef)CFReadStreamCopyProperty((CFReadStreamRef)[self readStream], kCFStreamPropertyHTTPResponseHeader);
- if (!message) {
- return;
- }
-
-
- if (!CFHTTPMessageIsHeaderComplete(message)) {
- CFRelease(message);
- return;
- }
- #if DEBUG_REQUEST_STATUS
- if ([self totalBytesSent] == [self postLength]) {
- ASI_DEBUG_LOG(@"[STATUS] Request %@ received response headers",self);
- }
- #endif
- [self setResponseHeaders:[NSMakeCollectable(CFHTTPMessageCopyAllHeaderFields(message)) autorelease]];
- [self setResponseStatusCode:(int)CFHTTPMessageGetResponseStatusCode(message)];
- [self setResponseStatusMessage:[NSMakeCollectable(CFHTTPMessageCopyResponseStatusLine(message)) autorelease]];
- if ([self downloadCache] && ([[self downloadCache] canUseCachedDataForRequest:self])) {
-
- [[self downloadCache] updateExpiryForRequest:self maxAge:[self secondsToCache]];
-
- [self useDataFromCache];
- CFRelease(message);
- return;
- }
-
- if ([self responseStatusCode] == 401) {
- [self setAuthenticationNeeded:ASIHTTPAuthenticationNeeded];
- } else if ([self responseStatusCode] == 407) {
- [self setAuthenticationNeeded:ASIProxyAuthenticationNeeded];
- } else {
- #if DEBUG_HTTP_AUTHENTICATION
- if ([self authenticationScheme]) {
- ASI_DEBUG_LOG(@"[AUTH] Request %@ has passed %@ authentication",self,[self authenticationScheme]);
- }
- #endif
- }
-
-
- if (![self authenticationNeeded]) {
-
- if (!requestAuthentication && [[self authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && [self username] && [self password] && [self useSessionPersistence]) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ passed BASIC authentication, and will save credentials in the session store for future use",self);
- #endif
-
- NSMutableDictionary *newCredentials = [NSMutableDictionary dictionaryWithCapacity:2];
- [newCredentials setObject:[self username] forKey:(NSString *)kCFHTTPAuthenticationUsername];
- [newCredentials setObject:[self password] forKey:(NSString *)kCFHTTPAuthenticationPassword];
-
-
- NSMutableDictionary *sessionCredentials = [NSMutableDictionary dictionary];
- [sessionCredentials setObject:newCredentials forKey:@"Credentials"];
- [sessionCredentials setObject:[self url] forKey:@"URL"];
- [sessionCredentials setObject:(NSString *)kCFHTTPAuthenticationSchemeBasic forKey:@"AuthenticationScheme"];
- [[self class] storeAuthenticationCredentialsInSessionStore:sessionCredentials];
- }
- }
-
- [self parseStringEncodingFromHeaders];
-
- NSArray *newCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:[self responseHeaders] forURL:[self url]];
- [self setResponseCookies:newCookies];
-
- if ([self useCookiePersistence]) {
-
-
- [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:newCookies forURL:[self url] mainDocumentURL:nil];
-
-
- NSHTTPCookie *cookie;
- for (cookie in newCookies) {
- [ASIHTTPRequest addSessionCookie:cookie];
- }
- }
-
-
- if (![self willRedirect]) {
-
- NSString *cLength = [responseHeaders valueForKey:@"Content-Length"];
- ASIHTTPRequest *theRequest = self;
- if ([self mainRequest]) {
- theRequest = [self mainRequest];
- }
- if (cLength) {
- unsigned long long length = strtoull([cLength UTF8String], NULL, 0);
-
- if ([self mainRequest] && [self allowCompressedResponse] && length == 20 && [self showAccurateProgress] && [self shouldResetDownloadProgress]) {
- [[self mainRequest] setShowAccurateProgress:NO];
- [[self mainRequest] incrementDownloadSizeBy:1];
- } else {
- [theRequest setContentLength:length];
- if ([self showAccurateProgress] && [self shouldResetDownloadProgress]) {
- [theRequest incrementDownloadSizeBy:(long long)[theRequest contentLength]+(long long)[theRequest partialDownloadSize]];
- }
- }
- } else if ([self showAccurateProgress] && [self shouldResetDownloadProgress]) {
- [theRequest setShowAccurateProgress:NO];
- [theRequest incrementDownloadSizeBy:1];
- }
- }
-
- if ([self shouldAttemptPersistentConnection]) {
-
- NSString *connectionHeader = [[[self responseHeaders] objectForKey:@"Connection"] lowercaseString];
- NSString *httpVersion = [NSMakeCollectable(CFHTTPMessageCopyVersion(message)) autorelease];
-
-
- if (![httpVersion isEqualToString:(NSString *)kCFHTTPVersion1_0] || [connectionHeader isEqualToString:@"keep-alive"]) {
-
- if (![connectionHeader isEqualToString:@"close"]) {
-
- NSString *keepAliveHeader = [[self responseHeaders] objectForKey:@"Keep-Alive"];
-
-
- if (keepAliveHeader) {
- int timeout = 0;
- int max = 0;
- NSScanner *scanner = [NSScanner scannerWithString:keepAliveHeader];
- [scanner scanString:@"timeout=" intoString:NULL];
- [scanner scanInt:&timeout];
- [scanner scanUpToString:@"max=" intoString:NULL];
- [scanner scanString:@"max=" intoString:NULL];
- [scanner scanInt:&max];
- if (max > 5) {
- [self setConnectionCanBeReused:YES];
- [self setPersistentConnectionTimeoutSeconds:timeout];
- #if DEBUG_PERSISTENT_CONNECTIONS
- ASI_DEBUG_LOG(@"[CONNECTION] Got a keep-alive header, will keep this connection open for %f seconds", [self persistentConnectionTimeoutSeconds]);
- #endif
- }
-
-
- } else {
- [self setConnectionCanBeReused:YES];
- #if DEBUG_PERSISTENT_CONNECTIONS
- ASI_DEBUG_LOG(@"[CONNECTION] Got no keep-alive header, will keep this connection open for %f seconds", [self persistentConnectionTimeoutSeconds]);
- #endif
- }
- }
- }
- }
- CFRelease(message);
- [self performSelectorOnMainThread:@selector(requestReceivedResponseHeaders:) withObject:[[[self responseHeaders] copy] autorelease] waitUntilDone:[NSThread isMainThread]];
- }
- - (BOOL)willRedirect
- {
-
- if (![self shouldRedirect] || ![responseHeaders valueForKey:@"Location"]) {
- return NO;
- }
-
- int responseCode = [self responseStatusCode];
- if (responseCode != 301 && responseCode != 302 && responseCode != 303 && responseCode != 307) {
- return NO;
- }
- [self performSelectorOnMainThread:@selector(requestRedirected) withObject:nil waitUntilDone:[NSThread isMainThread]];
-
-
-
-
- if (responseCode != 307 && (![self shouldUseRFC2616RedirectBehaviour] || responseCode == 303)) {
- [self setRequestMethod:@"GET"];
- [self setPostBody:nil];
- [self setPostLength:0];
-
- NSString *userAgentHeader = [[self requestHeaders] objectForKey:@"User-Agent"];
- NSString *acceptHeader = [[self requestHeaders] objectForKey:@"Accept"];
- [self setRequestHeaders:nil];
- if (userAgentHeader) {
- [self addRequestHeader:@"User-Agent" value:userAgentHeader];
- }
- if (acceptHeader) {
- [self addRequestHeader:@"Accept" value:acceptHeader];
- }
- [self setHaveBuiltRequestHeaders:NO];
- } else {
-
-
- [self applyCookieHeader];
- }
-
- [self setRedirectURL:[[NSURL URLWithString:[responseHeaders valueForKey:@"Location"] relativeToURL:[self url]] absoluteURL]];
- [self setNeedsRedirect:YES];
-
-
-
- [self setRequestCookies:[NSMutableArray array]];
- #if DEBUG_REQUEST_STATUS
- ASI_DEBUG_LOG(@"[STATUS] Request will redirect (code: %i): %@",responseCode,self);
- #endif
- return YES;
- }
- - (void)parseStringEncodingFromHeaders
- {
-
- NSStringEncoding charset = 0;
- NSString *mimeType = nil;
- [[self class] parseMimeType:&mimeType andResponseEncoding:&charset fromContentType:[[self responseHeaders] valueForKey:@"Content-Type"]];
- if (charset != 0) {
- [self setResponseEncoding:charset];
- } else {
- [self setResponseEncoding:[self defaultResponseEncoding]];
- }
- }
- #pragma mark http authentication
- - (void)saveProxyCredentialsToKeychain:(NSDictionary *)newCredentials
- {
- NSURLCredential *authenticationCredentials = [NSURLCredential credentialWithUser:[newCredentials objectForKey:(NSString *)kCFHTTPAuthenticationUsername] password:[newCredentials objectForKey:(NSString *)kCFHTTPAuthenticationPassword] persistence:NSURLCredentialPersistencePermanent];
- if (authenticationCredentials) {
- [ASIHTTPRequest saveCredentials:authenticationCredentials forProxy:[self proxyHost] port:[self proxyPort] realm:[self proxyAuthenticationRealm]];
- }
- }
- - (void)saveCredentialsToKeychain:(NSDictionary *)newCredentials
- {
- NSURLCredential *authenticationCredentials = [NSURLCredential credentialWithUser:[newCredentials objectForKey:(NSString *)kCFHTTPAuthenticationUsername] password:[newCredentials objectForKey:(NSString *)kCFHTTPAuthenticationPassword] persistence:NSURLCredentialPersistencePermanent];
-
- if (authenticationCredentials) {
- [ASIHTTPRequest saveCredentials:authenticationCredentials forHost:[[self url] host] port:[[[self url] port] intValue] protocol:[[self url] scheme] realm:[self authenticationRealm]];
- }
- }
- - (BOOL)applyProxyCredentials:(NSDictionary *)newCredentials
- {
- [self setProxyAuthenticationRetryCount:[self proxyAuthenticationRetryCount]+1];
-
- if (newCredentials && proxyAuthentication && request) {
-
- if (CFHTTPMessageApplyCredentialDictionary(request, proxyAuthentication, (CFMutableDictionaryRef)newCredentials, NULL)) {
-
-
- if (useKeychainPersistence) {
- [self saveProxyCredentialsToKeychain:newCredentials];
- }
- if (useSessionPersistence) {
- NSMutableDictionary *sessionProxyCredentials = [NSMutableDictionary dictionary];
- [sessionProxyCredentials setObject:(id)proxyAuthentication forKey:@"Authentication"];
- [sessionProxyCredentials setObject:newCredentials forKey:@"Credentials"];
- [sessionProxyCredentials setObject:[self proxyHost] forKey:@"Host"];
- [sessionProxyCredentials setObject:[NSNumber numberWithInt:[self proxyPort]] forKey:@"Port"];
- [sessionProxyCredentials setObject:[self proxyAuthenticationScheme] forKey:@"AuthenticationScheme"];
- [[self class] storeProxyAuthenticationCredentialsInSessionStore:sessionProxyCredentials];
- }
- [self setProxyCredentials:newCredentials];
- return YES;
- } else {
- [[self class] removeProxyAuthenticationCredentialsFromSessionStore:newCredentials];
- }
- }
- return NO;
- }
- - (BOOL)applyCredentials:(NSDictionary *)newCredentials
- {
- [self setAuthenticationRetryCount:[self authenticationRetryCount]+1];
-
- if (newCredentials && requestAuthentication && request) {
-
- if (CFHTTPMessageApplyCredentialDictionary(request, requestAuthentication, (CFMutableDictionaryRef)newCredentials, NULL)) {
-
-
- if (useKeychainPersistence) {
- [self saveCredentialsToKeychain:newCredentials];
- }
- if (useSessionPersistence) {
-
- NSMutableDictionary *sessionCredentials = [NSMutableDictionary dictionary];
- [sessionCredentials setObject:(id)requestAuthentication forKey:@"Authentication"];
- [sessionCredentials setObject:newCredentials forKey:@"Credentials"];
- [sessionCredentials setObject:[self url] forKey:@"URL"];
- [sessionCredentials setObject:[self authenticationScheme] forKey:@"AuthenticationScheme"];
- if ([self authenticationRealm]) {
- [sessionCredentials setObject:[self authenticationRealm] forKey:@"AuthenticationRealm"];
- }
- [[self class] storeAuthenticationCredentialsInSessionStore:sessionCredentials];
- }
- [self setRequestCredentials:newCredentials];
- return YES;
- } else {
- [[self class] removeAuthenticationCredentialsFromSessionStore:newCredentials];
- }
- }
- return NO;
- }
- - (NSMutableDictionary *)findProxyCredentials
- {
- NSMutableDictionary *newCredentials = [[[NSMutableDictionary alloc] init] autorelease];
-
- NSString *user = nil;
- NSString *pass = nil;
-
- ASIHTTPRequest *theRequest = [self mainRequest];
-
- if ([theRequest proxyUsername] && [theRequest proxyPassword]) {
- user = [theRequest proxyUsername];
- pass = [theRequest proxyPassword];
-
-
- } else if ([self proxyUsername] && [self proxyPassword]) {
- user = [self proxyUsername];
- pass = [self proxyPassword];
- }
-
- if ((!user || !pass) && [self proxyAuthenticationScheme] == (NSString *)kCFHTTPAuthenticationSchemeNTLM) {
- user = [self username];
- pass = [self password];
- }
-
-
-
- if ((!user || !pass)) {
- NSURLCredential *authenticationCredentials = [ASIHTTPRequest savedCredentialsForProxy:[self proxyHost] port:[self proxyPort] protocol:[[self url] scheme] realm:[self proxyAuthenticationRealm]];
- if (authenticationCredentials) {
- user = [authenticationCredentials user];
- pass = [authenticationCredentials password];
- }
-
- }
-
- if (CFHTTPAuthenticationRequiresAccountDomain(proxyAuthentication)) {
- NSString *ntlmDomain = [self proxyDomain];
-
- if (!ntlmDomain || [ntlmDomain length] == 0) {
-
- NSArray* ntlmComponents = [user componentsSeparatedByString:@"\\"];
- if ([ntlmComponents count] == 2) {
- ntlmDomain = [ntlmComponents objectAtIndex:0];
- user = [ntlmComponents objectAtIndex:1];
-
- } else {
- ntlmDomain = [self domain];
- }
- if (!ntlmDomain) {
- ntlmDomain = @"";
- }
- }
- [newCredentials setObject:ntlmDomain forKey:(NSString *)kCFHTTPAuthenticationAccountDomain];
- }
-
- if (user && pass) {
- [newCredentials setObject:user forKey:(NSString *)kCFHTTPAuthenticationUsername];
- [newCredentials setObject:pass forKey:(NSString *)kCFHTTPAuthenticationPassword];
- return newCredentials;
- }
- return nil;
- }
- - (NSMutableDictionary *)findCredentials
- {
- NSMutableDictionary *newCredentials = [[[NSMutableDictionary alloc] init] autorelease];
-
- NSString *user = [[self url] user];
- NSString *pass = [[self url] password];
- if (user && pass) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ will use credentials set on its url",self);
- #endif
- } else {
-
-
- if ([self mainRequest] && [[self mainRequest] username] && [[self mainRequest] password]) {
- user = [[self mainRequest] username];
- pass = [[self mainRequest] password];
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ will use credentials from its parent request",self);
- #endif
-
- } else if ([self username] && [self password]) {
- user = [self username];
- pass = [self password];
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ will use username and password properties as credentials",self);
- #endif
- }
- }
-
-
- if ((!user || !pass) && useKeychainPersistence) {
- NSURLCredential *authenticationCredentials = [ASIHTTPRequest savedCredentialsForHost:[[self url] host] port:[[[self url] port] intValue] protocol:[[self url] scheme] realm:[self authenticationRealm]];
- if (authenticationCredentials) {
- user = [authenticationCredentials user];
- pass = [authenticationCredentials password];
- #if DEBUG_HTTP_AUTHENTICATION
- if (user && pass) {
- ASI_DEBUG_LOG(@"[AUTH] Request %@ will use credentials from the keychain",self);
- }
- #endif
- }
- }
-
- if (CFHTTPAuthenticationRequiresAccountDomain(requestAuthentication)) {
- NSString *ntlmDomain = [self domain];
-
- if (!ntlmDomain || [ntlmDomain length] == 0) {
- ntlmDomain = @"";
- NSArray* ntlmComponents = [user componentsSeparatedByString:@"\\"];
- if ([ntlmComponents count] == 2) {
- ntlmDomain = [ntlmComponents objectAtIndex:0];
- user = [ntlmComponents objectAtIndex:1];
- }
- }
- [newCredentials setObject:ntlmDomain forKey:(NSString *)kCFHTTPAuthenticationAccountDomain];
- }
-
- if (user && pass) {
- [newCredentials setObject:user forKey:(NSString *)kCFHTTPAuthenticationUsername];
- [newCredentials setObject:pass forKey:(NSString *)kCFHTTPAuthenticationPassword];
- return newCredentials;
- }
- return nil;
- }
- - (void)retryUsingSuppliedCredentials
- {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ received credentials from its delegate or an ASIAuthenticationDialog, will retry",self);
- #endif
-
- if (!request) {
- [self performSelector:@selector(main) onThread:[[self class] threadForRequest:self] withObject:nil waitUntilDone:NO];
- return;
- }
- [self performSelector:@selector(attemptToApplyCredentialsAndResume) onThread:[[self class] threadForRequest:self] withObject:nil waitUntilDone:NO];
- }
- - (void)cancelAuthentication
- {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ had authentication cancelled by its delegate or an ASIAuthenticationDialog",self);
- #endif
- [self performSelector:@selector(failAuthentication) onThread:[[self class] threadForRequest:self] withObject:nil waitUntilDone:NO];
- }
- - (void)failAuthentication
- {
- [self failWithError:ASIAuthenticationError];
- }
- - (BOOL)showProxyAuthenticationDialog
- {
- if ([self isSynchronous]) {
- return NO;
- }
-
- #if TARGET_OS_IPHONE
- if ([self shouldPresentProxyAuthenticationDialog]) {
- [ASIAuthenticationDialog performSelectorOnMainThread:@selector(presentAuthenticationDialogForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]];
- return YES;
- }
- return NO;
- #else
- return NO;
- #endif
- }
- - (BOOL)willAskDelegateForProxyCredentials
- {
- if ([self isSynchronous]) {
- return NO;
- }
-
-
- id authenticationDelegate = [self delegate];
- if (!authenticationDelegate) {
- authenticationDelegate = [self queue];
- }
-
- BOOL delegateOrBlockWillHandleAuthentication = NO;
- if ([authenticationDelegate respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) {
- delegateOrBlockWillHandleAuthentication = YES;
- }
- #if NS_BLOCKS_AVAILABLE
- if(proxyAuthenticationNeededBlock){
- delegateOrBlockWillHandleAuthentication = YES;
- }
- #endif
- if (delegateOrBlockWillHandleAuthentication) {
- [self performSelectorOnMainThread:@selector(askDelegateForProxyCredentials) withObject:nil waitUntilDone:NO];
- }
-
- return delegateOrBlockWillHandleAuthentication;
- }
- - (void)askDelegateForProxyCredentials
- {
- id authenticationDelegate = [self delegate];
- if (!authenticationDelegate) {
- authenticationDelegate = [self queue];
- }
- if ([authenticationDelegate respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) {
- [authenticationDelegate performSelector:@selector(proxyAuthenticationNeededForRequest:) withObject:self];
- return;
- }
- #if NS_BLOCKS_AVAILABLE
- if(proxyAuthenticationNeededBlock){
- proxyAuthenticationNeededBlock();
- }
- #endif
- }
- - (BOOL)willAskDelegateForCredentials
- {
- if ([self isSynchronous]) {
- return NO;
- }
-
-
- id authenticationDelegate = [self delegate];
- if (!authenticationDelegate) {
- authenticationDelegate = [self queue];
- }
- BOOL delegateOrBlockWillHandleAuthentication = NO;
- if ([authenticationDelegate respondsToSelector:@selector(authenticationNeededForRequest:)]) {
- delegateOrBlockWillHandleAuthentication = YES;
- }
- #if NS_BLOCKS_AVAILABLE
- if (authenticationNeededBlock) {
- delegateOrBlockWillHandleAuthentication = YES;
- }
- #endif
- if (delegateOrBlockWillHandleAuthentication) {
- [self performSelectorOnMainThread:@selector(askDelegateForCredentials) withObject:nil waitUntilDone:NO];
- }
- return delegateOrBlockWillHandleAuthentication;
- }
- - (void)askDelegateForCredentials
- {
- id authenticationDelegate = [self delegate];
- if (!authenticationDelegate) {
- authenticationDelegate = [self queue];
- }
-
- if ([authenticationDelegate respondsToSelector:@selector(authenticationNeededForRequest:)]) {
- [authenticationDelegate performSelector:@selector(authenticationNeededForRequest:) withObject:self];
- return;
- }
-
- #if NS_BLOCKS_AVAILABLE
- if (authenticationNeededBlock) {
- authenticationNeededBlock();
- }
- #endif
- }
- - (void)attemptToApplyProxyCredentialsAndResume
- {
-
- if ([self error] || [self isCancelled]) {
- return;
- }
-
-
- if (!proxyAuthentication) {
- CFHTTPMessageRef responseHeader = (CFHTTPMessageRef) CFReadStreamCopyProperty((CFReadStreamRef)[self readStream],kCFStreamPropertyHTTPResponseHeader);
- proxyAuthentication = CFHTTPAuthenticationCreateFromResponse(NULL, responseHeader);
- CFRelease(responseHeader);
- [self setProxyAuthenticationScheme:[NSMakeCollectable(CFHTTPAuthenticationCopyMethod(proxyAuthentication)) autorelease]];
- }
-
-
- if (!proxyAuthentication) {
- [self cancelLoad];
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileApplyingCredentialsType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Failed to get authentication object from response headers",NSLocalizedDescriptionKey,nil]]];
- return;
- }
-
-
- [self setProxyAuthenticationRealm:nil];
- if (!CFHTTPAuthenticationRequiresAccountDomain(proxyAuthentication)) {
- [self setProxyAuthenticationRealm:[NSMakeCollectable(CFHTTPAuthenticationCopyRealm(proxyAuthentication)) autorelease]];
- }
-
-
- CFStreamError err;
- if (!CFHTTPAuthenticationIsValid(proxyAuthentication, &err)) {
-
- CFRelease(proxyAuthentication);
- proxyAuthentication = NULL;
-
-
- if (err.domain == kCFStreamErrorDomainHTTP && (err.error == kCFStreamErrorHTTPAuthenticationBadUserName || err.error == kCFStreamErrorHTTPAuthenticationBadPassword)) {
-
-
- [delegateAuthenticationLock lock];
-
-
- [[self class] removeProxyAuthenticationCredentialsFromSessionStore:proxyCredentials];
- [self setProxyCredentials:nil];
-
-
-
- if ([self error] || [self isCancelled]) {
- [delegateAuthenticationLock unlock];
- return;
- }
-
-
-
- if ([self useSessionPersistence]) {
- NSDictionary *credentials = [self findSessionProxyAuthenticationCredentials];
- if (credentials && [self applyProxyCredentials:[credentials objectForKey:@"Credentials"]]) {
- [delegateAuthenticationLock unlock];
- [self startRequest];
- return;
- }
- }
-
- [self setLastActivityTime:nil];
-
- if ([self willAskDelegateForProxyCredentials]) {
- [self attemptToApplyProxyCredentialsAndResume];
- [delegateAuthenticationLock unlock];
- return;
- }
- if ([self showProxyAuthenticationDialog]) {
- [self attemptToApplyProxyCredentialsAndResume];
- [delegateAuthenticationLock unlock];
- return;
- }
- [delegateAuthenticationLock unlock];
- }
- [self cancelLoad];
- [self failWithError:ASIAuthenticationError];
- return;
- }
- [self cancelLoad];
-
- if (proxyCredentials) {
-
-
- if ((([self proxyAuthenticationScheme] != (NSString *)kCFHTTPAuthenticationSchemeNTLM) || [self proxyAuthenticationRetryCount] < 2) && [self applyProxyCredentials:proxyCredentials]) {
- [self startRequest];
-
-
- } else if ([self proxyAuthenticationScheme] == (NSString *)kCFHTTPAuthenticationSchemeNTLM && [self proxyAuthenticationRetryCount] == 2) {
- [self failWithError:ASIAuthenticationError];
-
-
- } else {
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileApplyingCredentialsType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Failed to apply proxy credentials to request",NSLocalizedDescriptionKey,nil]]];
- }
-
-
- } else if (CFHTTPAuthenticationRequiresUserNameAndPassword(proxyAuthentication)) {
-
-
- [delegateAuthenticationLock lock];
-
-
- if ([self error] || [self isCancelled]) {
- [delegateAuthenticationLock unlock];
- return;
- }
-
-
- if ([self useSessionPersistence]) {
- NSDictionary *credentials = [self findSessionProxyAuthenticationCredentials];
- if (credentials && [self applyProxyCredentials:[credentials objectForKey:@"Credentials"]]) {
- [delegateAuthenticationLock unlock];
- [self startRequest];
- return;
- }
- }
-
- NSMutableDictionary *newCredentials = [self findProxyCredentials];
-
-
- if (newCredentials) {
-
- if ([self applyProxyCredentials:newCredentials]) {
- [delegateAuthenticationLock unlock];
- [self startRequest];
- } else {
- [delegateAuthenticationLock unlock];
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileApplyingCredentialsType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Failed to apply proxy credentials to request",NSLocalizedDescriptionKey,nil]]];
- }
-
- return;
- }
-
- if ([self willAskDelegateForProxyCredentials]) {
- [delegateAuthenticationLock unlock];
- return;
- }
-
- if ([self showProxyAuthenticationDialog]) {
- [delegateAuthenticationLock unlock];
- return;
- }
- [delegateAuthenticationLock unlock];
-
-
- [self failWithError:ASIAuthenticationError];
- return;
- }
-
- }
- - (BOOL)showAuthenticationDialog
- {
- if ([self isSynchronous]) {
- return NO;
- }
-
- #if TARGET_OS_IPHONE
- if ([self shouldPresentAuthenticationDialog]) {
- [ASIAuthenticationDialog performSelectorOnMainThread:@selector(presentAuthenticationDialogForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]];
- return YES;
- }
- return NO;
- #else
- return NO;
- #endif
- }
- - (void)attemptToApplyCredentialsAndResume
- {
- if ([self error] || [self isCancelled]) {
- return;
- }
-
-
- if ([self authenticationNeeded] == ASIProxyAuthenticationNeeded) {
- [self attemptToApplyProxyCredentialsAndResume];
- return;
- }
-
-
- if (!requestAuthentication) {
- CFHTTPMessageRef responseHeader = (CFHTTPMessageRef) CFReadStreamCopyProperty((CFReadStreamRef)[self readStream],kCFStreamPropertyHTTPResponseHeader);
- requestAuthentication = CFHTTPAuthenticationCreateFromResponse(NULL, responseHeader);
- CFRelease(responseHeader);
- [self setAuthenticationScheme:[NSMakeCollectable(CFHTTPAuthenticationCopyMethod(requestAuthentication)) autorelease]];
- }
-
- if (!requestAuthentication) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ failed to read authentication information from response headers",self);
- #endif
- [self cancelLoad];
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileApplyingCredentialsType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Failed to get authentication object from response headers",NSLocalizedDescriptionKey,nil]]];
- return;
- }
-
-
- [self setAuthenticationRealm:nil];
- if (!CFHTTPAuthenticationRequiresAccountDomain(requestAuthentication)) {
- [self setAuthenticationRealm:[NSMakeCollectable(CFHTTPAuthenticationCopyRealm(requestAuthentication)) autorelease]];
- }
-
- #if DEBUG_HTTP_AUTHENTICATION
- NSString *realm = [self authenticationRealm];
- if (realm) {
- realm = [NSString stringWithFormat:@" (Realm: %@)",realm];
- } else {
- realm = @"";
- }
- if ([self authenticationScheme] != (NSString *)kCFHTTPAuthenticationSchemeNTLM || [self authenticationRetryCount] == 0) {
- ASI_DEBUG_LOG(@"[AUTH] Request %@ received 401 challenge and must authenticate using %@%@",self,[self authenticationScheme],realm);
- } else {
- ASI_DEBUG_LOG(@"[AUTH] Request %@ NTLM handshake step %i",self,[self authenticationRetryCount]+1);
- }
- #endif
-
- CFStreamError err;
- if (!CFHTTPAuthenticationIsValid(requestAuthentication, &err)) {
-
- CFRelease(requestAuthentication);
- requestAuthentication = NULL;
-
-
- if (err.domain == kCFStreamErrorDomainHTTP && (err.error == kCFStreamErrorHTTPAuthenticationBadUserName || err.error == kCFStreamErrorHTTPAuthenticationBadPassword)) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ had bad credentials, will remove them from the session store if they are cached",self);
- #endif
-
- [delegateAuthenticationLock lock];
-
-
- [[self class] removeAuthenticationCredentialsFromSessionStore:requestCredentials];
- [self setRequestCredentials:nil];
-
-
- if ([self error] || [self isCancelled]) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ failed or was cancelled while waiting to access credentials",self);
- #endif
- [delegateAuthenticationLock unlock];
- return;
- }
-
- if ([self useSessionPersistence]) {
- NSDictionary *credentials = [self findSessionAuthenticationCredentials];
- if (credentials && [self applyCredentials:[credentials objectForKey:@"Credentials"]]) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ will reuse cached credentials from the session (%@)",self,[credentials objectForKey:@"AuthenticationScheme"]);
- #endif
- [delegateAuthenticationLock unlock];
- [self startRequest];
- return;
- }
- }
-
- [self setLastActivityTime:nil];
-
- if ([self willAskDelegateForCredentials]) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ will ask its delegate for credentials to use",self);
- #endif
- [delegateAuthenticationLock unlock];
- return;
- }
- if ([self showAuthenticationDialog]) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ will ask ASIAuthenticationDialog for credentials",self);
- #endif
- [delegateAuthenticationLock unlock];
- return;
- }
- [delegateAuthenticationLock unlock];
- }
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ has no credentials to present and must give up",self);
- #endif
- [self cancelLoad];
- [self failWithError:ASIAuthenticationError];
- return;
- }
-
- [self cancelLoad];
-
- if (requestCredentials) {
-
- if ((([self authenticationScheme] != (NSString *)kCFHTTPAuthenticationSchemeNTLM) || [self authenticationRetryCount] < 2) && [self applyCredentials:requestCredentials]) {
- [self startRequest];
-
-
- } else if ([self authenticationScheme] == (NSString *)kCFHTTPAuthenticationSchemeNTLM && [self authenticationRetryCount ] == 2) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ has failed NTLM authentication",self);
- #endif
- [self failWithError:ASIAuthenticationError];
-
- } else {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ had credentials and they were not marked as bad, but we got a 401 all the same.",self);
- #endif
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileApplyingCredentialsType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Failed to apply credentials to request",NSLocalizedDescriptionKey,nil]]];
- }
-
-
- } else if (CFHTTPAuthenticationRequiresUserNameAndPassword(requestAuthentication)) {
-
-
- [delegateAuthenticationLock lock];
-
-
- if ([self error] || [self isCancelled]) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ failed or was cancelled while waiting to access credentials",self);
- #endif
- [delegateAuthenticationLock unlock];
- return;
- }
-
-
- if ([self useSessionPersistence]) {
- NSDictionary *credentials = [self findSessionAuthenticationCredentials];
- if (credentials && [self applyCredentials:[credentials objectForKey:@"Credentials"]]) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ will reuse cached credentials from the session (%@)",self,[credentials objectForKey:@"AuthenticationScheme"]);
- #endif
- [delegateAuthenticationLock unlock];
- [self startRequest];
- return;
- }
- }
-
- NSMutableDictionary *newCredentials = [self findCredentials];
-
-
- if (newCredentials) {
-
- if ([self applyCredentials:newCredentials]) {
- [delegateAuthenticationLock unlock];
- [self startRequest];
- } else {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ failed to apply credentials",self);
- #endif
- [delegateAuthenticationLock unlock];
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileApplyingCredentialsType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Failed to apply credentials to request",NSLocalizedDescriptionKey,nil]]];
- }
- return;
- }
- if ([self willAskDelegateForCredentials]) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ will ask its delegate for credentials to use",self);
- #endif
- [delegateAuthenticationLock unlock];
- return;
- }
- if ([self showAuthenticationDialog]) {
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ will ask ASIAuthenticationDialog for credentials",self);
- #endif
- [delegateAuthenticationLock unlock];
- return;
- }
- #if DEBUG_HTTP_AUTHENTICATION
- ASI_DEBUG_LOG(@"[AUTH] Request %@ has no credentials to present and must give up",self);
- #endif
- [delegateAuthenticationLock unlock];
- [self failWithError:ASIAuthenticationError];
- return;
- }
-
- }
- - (void)addBasicAuthenticationHeaderWithUsername:(NSString *)theUsername andPassword:(NSString *)thePassword
- {
- [self addRequestHeader:@"Authorization" value:[NSString stringWithFormat:@"Basic %@",[ASIHTTPRequest base64forData:[[NSString stringWithFormat:@"%@:%@",theUsername,thePassword] dataUsingEncoding:NSUTF8StringEncoding]]]];
- [self setAuthenticationScheme:(NSString *)kCFHTTPAuthenticationSchemeBasic];
- }
- #pragma mark stream status handlers
- - (void)handleNetworkEvent:(CFStreamEventType)type
- {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [[self cancelledLock] lock];
-
- if ([self complete] || [self isCancelled]) {
- [[self cancelledLock] unlock];
- [pool drain];
- return;
- }
- CFRetain(self);
-
- switch (type) {
- case kCFStreamEventHasBytesAvailable:
- [self handleBytesAvailable];
- break;
-
- case kCFStreamEventEndEncountered:
- [self handleStreamComplete];
- break;
-
- case kCFStreamEventErrorOccurred:
- [self handleStreamError];
- break;
-
- default:
- break;
- }
-
- [self performThrottling];
-
- [[self cancelledLock] unlock];
-
- if ([self downloadComplete] && [self needsRedirect]) {
- if (![self willAskDelegateToConfirmRedirect]) {
- [self performRedirect];
- }
- } else if ([self downloadComplete] && [self authenticationNeeded]) {
- [self attemptToApplyCredentialsAndResume];
- }
- CFRelease(self);
- [pool drain];
- }
- - (BOOL)willAskDelegateToConfirmRedirect
- {
-
- [[self cancelledLock] lock];
-
-
- BOOL needToAskDelegateAboutRedirect = (([self delegate] && [[self delegate] respondsToSelector:[self willRedirectSelector]]) || ([self queue] && [[self queue] respondsToSelector:@selector(request:willRedirectToURL:)]));
- [[self cancelledLock] unlock];
-
- if (needToAskDelegateAboutRedirect) {
- NSURL *newURL = [[[self redirectURL] copy] autorelease];
- [self setRedirectURL:nil];
- [self performSelectorOnMainThread:@selector(requestWillRedirectToURL:) withObject:newURL waitUntilDone:[NSThread isMainThread]];
- return true;
- }
- return false;
- }
- - (void)handleBytesAvailable
- {
- if (![self responseHeaders]) {
- [self readResponseHeaders];
- }
-
-
- if ([self complete]) {
- return;
- }
-
-
-
-
- if (!CFReadStreamHasBytesAvailable((CFReadStreamRef)[self readStream])) {
- return;
- }
- long long bufferSize = 16384;
- if (contentLength > 262144) {
- bufferSize = 262144;
- } else if (contentLength > 65536) {
- bufferSize = 65536;
- }
-
-
-
-
- if ([[self class] isBandwidthThrottled]) {
- [bandwidthThrottlingLock lock];
- if (maxBandwidthPerSecond > 0) {
- long long maxiumumSize = (long long)maxBandwidthPerSecond-(long long)bandwidthUsedInLastSecond;
- if (maxiumumSize < 0) {
-
- bufferSize = 1;
- } else if (maxiumumSize/4 < bufferSize) {
-
- bufferSize = maxiumumSize/4;
- }
- }
- if (bufferSize < 1) {
- bufferSize = 1;
- }
- [bandwidthThrottlingLock unlock];
- }
-
-
- UInt8 buffer[bufferSize];
- NSInteger bytesRead = [[self readStream] read:buffer maxLength:sizeof(buffer)];
-
- if (bytesRead < 0) {
- [self handleStreamError];
-
-
- } else if (bytesRead) {
-
- NSData *inflatedData = nil;
- if ([self isResponseCompressed] && ![self shouldWaitToInflateCompressedResponses]) {
- if (![self dataDecompressor]) {
- [self setDataDecompressor:[ASIDataDecompressor decompressor]];
- }
- NSError *err = nil;
- inflatedData = [[self dataDecompressor] uncompressBytes:buffer length:(NSUInteger)bytesRead error:&err];
- if (err) {
- [self failWithError:err];
- return;
- }
- }
-
- [self setTotalBytesRead:[self totalBytesRead]+(NSUInteger)bytesRead];
- [self setLastActivityTime:[NSDate date]];
-
- [ASIHTTPRequest incrementBandwidthUsedInLastSecond:(NSUInteger)bytesRead];
-
-
- if ([self needsRedirect] && [self shouldRedirect] && [self allowResumeForFileDownloads]) {
- return;
- }
-
- BOOL dataWillBeHandledExternally = NO;
- if ([[self delegate] respondsToSelector:[self didReceiveDataSelector]]) {
- dataWillBeHandledExternally = YES;
- }
- #if NS_BLOCKS_AVAILABLE
- if (dataReceivedBlock) {
- dataWillBeHandledExternally = YES;
- }
- #endif
-
- if (dataWillBeHandledExternally) {
- NSData *data = nil;
- if ([self isResponseCompressed] && ![self shouldWaitToInflateCompressedResponses]) {
- data = inflatedData;
- } else {
- data = [NSData dataWithBytes:buffer length:(NSUInteger)bytesRead];
- }
- [self performSelectorOnMainThread:@selector(passOnReceivedData:) withObject:data waitUntilDone:[NSThread isMainThread]];
-
-
- } else if ([self downloadDestinationPath]) {
- BOOL append = NO;
- if (![self fileDownloadOutputStream]) {
- if (![self temporaryFileDownloadPath]) {
- [self setTemporaryFileDownloadPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]];
- } else if ([self allowResumeForFileDownloads] && [[self requestHeaders] objectForKey:@"Range"]) {
- if ([[self responseHeaders] objectForKey:@"Content-Range"]) {
- append = YES;
- } else {
- [self incrementDownloadSizeBy:-(long long)[self partialDownloadSize]];
- [self setPartialDownloadSize:0];
- }
- }
- [self setFileDownloadOutputStream:[[[NSOutputStream alloc] initToFileAtPath:[self temporaryFileDownloadPath] append:append] autorelease]];
- [[self fileDownloadOutputStream] open];
- }
- [[self fileDownloadOutputStream] write:buffer maxLength:(NSUInteger)bytesRead];
- if ([self isResponseCompressed] && ![self shouldWaitToInflateCompressedResponses]) {
-
- if (![self inflatedFileDownloadOutputStream]) {
- if (![self temporaryUncompressedDataDownloadPath]) {
- [self setTemporaryUncompressedDataDownloadPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]];
- }
-
- [self setInflatedFileDownloadOutputStream:[[[NSOutputStream alloc] initToFileAtPath:[self temporaryUncompressedDataDownloadPath] append:append] autorelease]];
- [[self inflatedFileDownloadOutputStream] open];
- }
- [[self inflatedFileDownloadOutputStream] write:[inflatedData bytes] maxLength:[inflatedData length]];
- }
-
-
- } else {
- if ([self isResponseCompressed] && ![self shouldWaitToInflateCompressedResponses]) {
- [rawResponseData appendData:inflatedData];
- } else {
- [rawResponseData appendBytes:buffer length:(NSUInteger)bytesRead];
- }
- }
- }
- }
- - (void)handleStreamComplete
- {
- #if DEBUG_REQUEST_STATUS
- ASI_DEBUG_LOG(@"[STATUS] Request %@ finished downloading data (%qu bytes)",self, [self totalBytesRead]);
- #endif
- [self setStatusTimer:nil];
- [self setDownloadComplete:YES];
-
- if (![self responseHeaders]) {
- [self readResponseHeaders];
- }
- [progressLock lock];
-
- [self setLastBytesSent:totalBytesSent];
- [self setTotalBytesSent:[[NSMakeCollectable(CFReadStreamCopyProperty((CFReadStreamRef)[self readStream], kCFStreamPropertyHTTPRequestBytesWrittenCount)) autorelease] unsignedLongLongValue]];
- [self setComplete:YES];
- if (![self contentLength]) {
- [self setContentLength:[self totalBytesRead]];
- }
- [self updateProgressIndicators];
-
- [[self postBodyReadStream] close];
- [self setPostBodyReadStream:nil];
-
- [self setDataDecompressor:nil];
- NSError *fileError = nil;
-
-
- if ([self didCreateTemporaryPostDataFile] && ![self authenticationNeeded]) {
- [self removeTemporaryUploadFile];
- [self removeTemporaryCompressedUploadFile];
- }
-
-
- if ([self temporaryFileDownloadPath]) {
-
- [[self fileDownloadOutputStream] close];
- [self setFileDownloadOutputStream:nil];
- [[self inflatedFileDownloadOutputStream] close];
- [self setInflatedFileDownloadOutputStream:nil];
-
- if ([self shouldRedirect] && [self needsRedirect] && [self allowResumeForFileDownloads]) {
-
- } else if ([self isResponseCompressed]) {
-
-
- if ([self shouldWaitToInflateCompressedResponses]) {
- [ASIDataDecompressor uncompressDataFromFile:[self temporaryFileDownloadPath] toFile:[self downloadDestinationPath] error:&fileError];
-
- } else {
- NSError *moveError = nil;
- [[[[NSFileManager alloc] init] autorelease] moveItemAtPath:[self temporaryUncompressedDataDownloadPath] toPath:[self downloadDestinationPath] error:&moveError];
- if (moveError) {
- fileError = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASIFileManagementError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Failed to move file from '%@' to '%@'",[self temporaryFileDownloadPath],[self downloadDestinationPath]],NSLocalizedDescriptionKey,moveError,NSUnderlyingErrorKey,nil]];
- }
- [self setTemporaryUncompressedDataDownloadPath:nil];
- }
- [self removeTemporaryDownloadFile];
- } else {
-
-
- NSError *moveError = nil;
- if (![[self class] removeFileAtPath:[self downloadDestinationPath] error:&moveError]) {
- fileError = moveError;
- }
-
- if (!fileError) {
- [[[[NSFileManager alloc] init] autorelease] moveItemAtPath:[self temporaryFileDownloadPath] toPath:[self downloadDestinationPath] error:&moveError];
- if (moveError) {
- fileError = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASIFileManagementError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Failed to move file from '%@' to '%@'",[self temporaryFileDownloadPath],[self downloadDestinationPath]],NSLocalizedDescriptionKey,moveError,NSUnderlyingErrorKey,nil]];
- }
- [self setTemporaryFileDownloadPath:nil];
- }
-
- }
- }
-
-
- if ([self downloadCache] && ![self didUseCachedResponse]) {
- [[self downloadCache] storeResponseForRequest:self maxAge:[self secondsToCache]];
- }
-
- [progressLock unlock];
-
- [connectionsLock lock];
- if (![self connectionCanBeReused]) {
- [self unscheduleReadStream];
- }
- #if DEBUG_PERSISTENT_CONNECTIONS
- if ([self requestID]) {
- ASI_DEBUG_LOG(@"[CONNECTION] Request #%@ finished using connection #%@",[self requestID], [[self connectionInfo] objectForKey:@"id"]);
- }
- #endif
- [[self connectionInfo] removeObjectForKey:@"request"];
- [[self connectionInfo] setObject:[NSDate dateWithTimeIntervalSinceNow:[self persistentConnectionTimeoutSeconds]] forKey:@"expires"];
- [connectionsLock unlock];
-
- if (![self authenticationNeeded]) {
- [self destroyReadStream];
- }
-
- if (![self needsRedirect] && ![self authenticationNeeded] && ![self didUseCachedResponse]) {
-
- if (fileError) {
- [self failWithError:fileError];
- } else {
- [self requestFinished];
- }
- [self markAsFinished];
-
-
- } else if ([self authenticationNeeded]) {
-
- }
- }
- - (void)markAsFinished
- {
-
- CFRetain(self);
-
- if (request) {
- CFRelease(request);
- request = nil;
- }
- if (requestAuthentication) {
- CFRelease(requestAuthentication);
- requestAuthentication = nil;
- }
- if (proxyAuthentication) {
- CFRelease(proxyAuthentication);
- proxyAuthentication = nil;
- }
- BOOL wasInProgress = inProgress;
- BOOL wasFinished = finished;
- if (!wasFinished)
- [self willChangeValueForKey:@"isFinished"];
- if (wasInProgress)
- [self willChangeValueForKey:@"isExecuting"];
- [self setInProgress:NO];
- finished = YES;
- if (wasInProgress)
- [self didChangeValueForKey:@"isExecuting"];
- if (!wasFinished)
- [self didChangeValueForKey:@"isFinished"];
- #if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
- if ([ASIHTTPRequest isMultitaskingSupported] && [self shouldContinueWhenAppEntersBackground]) {
- dispatch_async(dispatch_get_main_queue(), ^{
- if (backgroundTask != UIBackgroundTaskInvalid) {
- [[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
- backgroundTask = UIBackgroundTaskInvalid;
- }
- });
- }
- #endif
- CFRelease(self);
- }
- - (void)useDataFromCache
- {
- NSDictionary *headers = [[self downloadCache] cachedResponseHeadersForURL:[self url]];
- NSString *dataPath = [[self downloadCache] pathToCachedResponseDataForURL:[self url]];
- ASIHTTPRequest *theRequest = self;
- if ([self mainRequest]) {
- theRequest = [self mainRequest];
- }
- if (headers && dataPath) {
- [self setResponseStatusCode:[[headers objectForKey:@"X-ASIHTTPRequest-Response-Status-Code"] intValue]];
- [self setDidUseCachedResponse:YES];
- [theRequest setResponseHeaders:headers];
- if ([theRequest downloadDestinationPath]) {
- [theRequest setDownloadDestinationPath:dataPath];
- } else {
- [theRequest setRawResponseData:[NSMutableData dataWithData:[[self downloadCache] cachedResponseDataForURL:[self url]]]];
- }
- [theRequest setContentLength:(unsigned long long)[[[self responseHeaders] objectForKey:@"Content-Length"] longLongValue]];
- [theRequest setTotalBytesRead:[self contentLength]];
- [theRequest parseStringEncodingFromHeaders];
- [theRequest setResponseCookies:[NSHTTPCookie cookiesWithResponseHeaderFields:headers forURL:[self url]]];
-
- if ([self willRedirect]) {
- if (![self willAskDelegateToConfirmRedirect]) {
- [self performRedirect];
- }
- return;
- }
- }
- [theRequest setComplete:YES];
- [theRequest setDownloadComplete:YES];
-
- if ([self redirectCount] == 0) {
- [theRequest setOriginalURL:[theRequest url]];
- }
- [theRequest updateProgressIndicators];
- [theRequest requestFinished];
- [theRequest markAsFinished];
- if ([self mainRequest]) {
- [self markAsFinished];
- }
- }
- - (BOOL)retryUsingNewConnection
- {
- if ([self retryCount] == 0) {
- [self setWillRetryRequest:YES];
- [self cancelLoad];
- [self setWillRetryRequest:NO];
- #if DEBUG_PERSISTENT_CONNECTIONS
- ASI_DEBUG_LOG(@"[CONNECTION] Request attempted to use connection #%@, but it has been closed - will retry with a new connection", [[self connectionInfo] objectForKey:@"id"]);
- #endif
- [connectionsLock lock];
- [[self connectionInfo] removeObjectForKey:@"request"];
- [persistentConnectionsPool removeObject:[self connectionInfo]];
- [self setConnectionInfo:nil];
- [connectionsLock unlock];
- [self setRetryCount:[self retryCount]+1];
- [self startRequest];
- return YES;
- }
- #if DEBUG_PERSISTENT_CONNECTIONS
- ASI_DEBUG_LOG(@"[CONNECTION] Request attempted to use connection #%@, but it has been closed - we have already retried with a new connection, so we must give up", [[self connectionInfo] objectForKey:@"id"]);
- #endif
- return NO;
- }
- - (void)handleStreamError
- {
- NSError *underlyingError = [NSMakeCollectable(CFReadStreamCopyError((CFReadStreamRef)[self readStream])) autorelease];
- if (![self error]) {
-
-
-
-
-
-
- if (([[underlyingError domain] isEqualToString:NSPOSIXErrorDomain] && ([underlyingError code] == ENOTCONN || [underlyingError code] == EPIPE))
- || ([[underlyingError domain] isEqualToString:(NSString *)kCFErrorDomainCFNetwork] && [underlyingError code] == -1005)) {
- if ([self retryUsingNewConnection]) {
- return;
- }
- }
-
- NSString *reason = @"A connection failure occurred";
-
-
-
-
- if ([[underlyingError domain] isEqualToString:NSOSStatusErrorDomain]) {
- if ([underlyingError code] <= -9800 && [underlyingError code] >= -9818) {
- reason = [NSString stringWithFormat:@"%@: SSL problem (Possible causes may include a bad/expired/self-signed certificate, clock set to wrong date)",reason];
- }
- }
- [self cancelLoad];
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIConnectionFailureErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:reason,NSLocalizedDescriptionKey,underlyingError,NSUnderlyingErrorKey,nil]]];
- } else {
- [self cancelLoad];
- }
- [self checkRequestStatus];
- }
- #pragma mark managing the read stream
- - (void)destroyReadStream
- {
- if ([self readStream]) {
- [self unscheduleReadStream];
- if (![self connectionCanBeReused]) {
- [[self readStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:[self runLoopMode]];
- [[self readStream] close];
- }
- [self setReadStream:nil];
- }
- }
- - (void)scheduleReadStream
- {
- if ([self readStream] && ![self readStreamIsScheduled]) {
- [connectionsLock lock];
- runningRequestCount++;
- if (shouldUpdateNetworkActivityIndicator) {
- [[self class] showNetworkActivityIndicator];
- }
- [connectionsLock unlock];
-
- [self setLastActivityTime:[NSDate date]];
- CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL};
- CFReadStreamSetClient((CFReadStreamRef)[self readStream], kNetworkEvents, ReadStreamClientCallBack, &ctxt);
- [[self readStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:[self runLoopMode]];
- [self setReadStreamIsScheduled:YES];
- }
- }
- - (void)unscheduleReadStream
- {
- if ([self readStream] && [self readStreamIsScheduled]) {
- [connectionsLock lock];
- runningRequestCount--;
- if (shouldUpdateNetworkActivityIndicator && runningRequestCount == 0) {
-
-
-
-
- [[self class] performSelectorOnMainThread:@selector(hideNetworkActivityIndicatorAfterDelay) withObject:nil waitUntilDone:[NSThread isMainThread]];
- }
- [connectionsLock unlock];
- CFReadStreamSetClient((CFReadStreamRef)[self readStream], kCFStreamEventNone, NULL, NULL);
- [[self readStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:[self runLoopMode]];
- [self setReadStreamIsScheduled:NO];
- }
- }
- #pragma mark cleanup
- - (BOOL)removeTemporaryDownloadFile
- {
- NSError *err = nil;
- if ([self temporaryFileDownloadPath]) {
- if (![[self class] removeFileAtPath:[self temporaryFileDownloadPath] error:&err]) {
- [self failWithError:err];
- }
- [self setTemporaryFileDownloadPath:nil];
- }
- return (!err);
- }
- - (BOOL)removeTemporaryUncompressedDownloadFile
- {
- NSError *err = nil;
- if ([self temporaryUncompressedDataDownloadPath]) {
- if (![[self class] removeFileAtPath:[self temporaryUncompressedDataDownloadPath] error:&err]) {
- [self failWithError:err];
- }
- [self setTemporaryUncompressedDataDownloadPath:nil];
- }
- return (!err);
- }
- - (BOOL)removeTemporaryUploadFile
- {
- NSError *err = nil;
- if ([self postBodyFilePath]) {
- if (![[self class] removeFileAtPath:[self postBodyFilePath] error:&err]) {
- [self failWithError:err];
- }
- [self setPostBodyFilePath:nil];
- }
- return (!err);
- }
- - (BOOL)removeTemporaryCompressedUploadFile
- {
- NSError *err = nil;
- if ([self compressedPostBodyFilePath]) {
- if (![[self class] removeFileAtPath:[self compressedPostBodyFilePath] error:&err]) {
- [self failWithError:err];
- }
- [self setCompressedPostBodyFilePath:nil];
- }
- return (!err);
- }
- + (BOOL)removeFileAtPath:(NSString *)path error:(NSError **)err
- {
- NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
- if ([fileManager fileExistsAtPath:path]) {
- NSError *removeError = nil;
- [fileManager removeItemAtPath:path error:&removeError];
- if (removeError) {
- if (err) {
- *err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASIFileManagementError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Failed to delete file at path '%@'",path],NSLocalizedDescriptionKey,removeError,NSUnderlyingErrorKey,nil]];
- }
- return NO;
- }
- }
- return YES;
- }
- #pragma mark Proxies
- - (BOOL)configureProxies
- {
-
- if (![self isPACFileRequest] && (![self proxyHost] && ![self proxyPort])) {
-
- NSArray *proxies = nil;
-
- if ([self PACurl]) {
-
- [self fetchPACFile];
- return NO;
-
- } else {
- #if TARGET_OS_IPHONE
- NSDictionary *proxySettings = [NSMakeCollectable(CFNetworkCopySystemProxySettings()) autorelease];
- #else
- NSDictionary *proxySettings = [NSMakeCollectable(SCDynamicStoreCopyProxies(NULL)) autorelease];
- #endif
- proxies = [NSMakeCollectable(CFNetworkCopyProxiesForURL((CFURLRef)[self url], (CFDictionaryRef)proxySettings)) autorelease];
-
- NSDictionary *settings = [proxies objectAtIndex:0];
- if ([settings objectForKey:(NSString *)kCFProxyAutoConfigurationURLKey]) {
- [self setPACurl:[settings objectForKey:(NSString *)kCFProxyAutoConfigurationURLKey]];
- [self fetchPACFile];
- return NO;
- }
- }
- if (!proxies) {
- [self setReadStream:nil];
- [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to obtain information on proxy servers needed for request",NSLocalizedDescriptionKey,nil]]];
- return NO;
- }
-
-
- if ([proxies count] > 0) {
- NSDictionary *settings = [proxies objectAtIndex:0];
- [self setProxyHost:[settings objectForKey:(NSString *)kCFProxyHostNameKey]];
- [self setProxyPort:[[settings objectForKey:(NSString *)kCFProxyPortNumberKey] intValue]];
- [self setProxyType:[settings objectForKey:(NSString *)kCFProxyTypeKey]];
- }
- }
- return YES;
- }
- - (void)fetchPACFile
- {
-
- if ([[self PACurl] isFileURL]) {
- NSInputStream *stream = [[[NSInputStream alloc] initWithFileAtPath:[[self PACurl] path]] autorelease];
- [self setPACFileReadStream:stream];
- [stream setDelegate:(id)self];
- [stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:[self runLoopMode]];
- [stream open];
-
-
-
- [self performSelector:@selector(timeOutPACRead) withObject:nil afterDelay:[self timeOutSeconds]];
- return;
- }
- NSString *scheme = [[[self PACurl] scheme] lowercaseString];
- if (![scheme isEqualToString:@"http"] && ![scheme isEqualToString:@"https"]) {
-
-
- [self startRequest];
- return;
- }
-
- ASIHTTPRequest *PACRequest = [ASIHTTPRequest requestWithURL:[self PACurl]];
-
- [PACRequest setIsPACFileRequest:YES];
- [PACRequest setTimeOutSeconds:[self timeOutSeconds]];
-
- if ([self isSynchronous]) {
- [PACRequest startSynchronous];
- if (![PACRequest error] && [PACRequest responseString]) {
- [self runPACScript:[PACRequest responseString]];
- }
- [self startRequest];
- return;
- }
- [self setPACFileRequest:PACRequest];
-
- [PACRequest setQueuePriority:NSOperationQueuePriorityHigh];
-
- [PACRequest setDelegate:self];
- [PACRequest setDidFinishSelector:@selector(finishedDownloadingPACFile:)];
- [PACRequest setDidFailSelector:@selector(finishedDownloadingPACFile:)];
- [PACRequest startAsynchronous];
-
- [connectionsLock lock];
- [sharedQueue setMaxConcurrentOperationCount:[sharedQueue maxConcurrentOperationCount]+1];
- [connectionsLock unlock];
- }
- - (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
- {
- if (![self PACFileReadStream]) {
- return;
- }
- if (eventCode == NSStreamEventHasBytesAvailable) {
- if (![self PACFileData]) {
- [self setPACFileData:[NSMutableData data]];
- }
-
- uint8_t buf[16384];
- NSInteger len = [(NSInputStream *)stream read:buf maxLength:16384];
-
- if (len > 0) {
- [[self PACFileData] appendBytes:(const void *)buf length:(NSUInteger)len];
- }
- } else if (eventCode == NSStreamEventErrorOccurred || eventCode == NSStreamEventEndEncountered) {
- [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(timeOutPACRead) object:nil];
- [stream close];
- [stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:[self runLoopMode]];
- [self setPACFileReadStream:nil];
- if (eventCode == NSStreamEventEndEncountered) {
-
- static NSStringEncoding encodingsToTry[2] = {NSUTF8StringEncoding,NSISOLatin1StringEncoding};
- NSUInteger i;
- for (i=0; i<2; i++) {
- NSString *pacScript = [[[NSString alloc] initWithBytes:[[self PACFileData] bytes] length:[[self PACFileData] length] encoding:encodingsToTry[i]] autorelease];
- if (pacScript) {
- [self runPACScript:pacScript];
- break;
- }
- }
- }
- [self setPACFileData:nil];
- [self startRequest];
- }
- }
- - (void)timeOutPACRead
- {
- [self stream:[self PACFileReadStream] handleEvent:NSStreamEventErrorOccurred];
- }
- - (void)runPACScript:(NSString *)script
- {
- if (script) {
-
-
-
-
- CFRelease(CFNetworkCopyProxiesForURL((CFURLRef)[self url], NULL));
-
- CFErrorRef err = NULL;
- NSArray *proxies = [NSMakeCollectable(CFNetworkCopyProxiesForAutoConfigurationScript((CFStringRef)script,(CFURLRef)[self url], &err)) autorelease];
- if (!err && [proxies count] > 0) {
- NSDictionary *settings = [proxies objectAtIndex:0];
- [self setProxyHost:[settings objectForKey:(NSString *)kCFProxyHostNameKey]];
- [self setProxyPort:[[settings objectForKey:(NSString *)kCFProxyPortNumberKey] intValue]];
- [self setProxyType:[settings objectForKey:(NSString *)kCFProxyTypeKey]];
- }
- }
- }
- - (void)finishedDownloadingPACFile:(ASIHTTPRequest *)theRequest
- {
- if (![theRequest error] && [theRequest responseString]) {
- [self runPACScript:[theRequest responseString]];
- }
-
- [connectionsLock lock];
- [sharedQueue setMaxConcurrentOperationCount:[sharedQueue maxConcurrentOperationCount]-1];
- [connectionsLock unlock];
-
- [self setPACFileRequest:nil];
-
- [self startRequest];
- }
- #pragma mark persistent connections
- - (NSNumber *)connectionID
- {
- return [[self connectionInfo] objectForKey:@"id"];
- }
- + (void)expirePersistentConnections
- {
- [connectionsLock lock];
- NSUInteger i;
- for (i=0; i<[persistentConnectionsPool count]; i++) {
- NSDictionary *existingConnection = [persistentConnectionsPool objectAtIndex:i];
- if (![existingConnection objectForKey:@"request"] && [[existingConnection objectForKey:@"expires"] timeIntervalSinceNow] <= 0) {
- #if DEBUG_PERSISTENT_CONNECTIONS
- ASI_DEBUG_LOG(@"[CONNECTION] Closing connection #%i because it has expired",[[existingConnection objectForKey:@"id"] intValue]);
- #endif
- NSInputStream *stream = [existingConnection objectForKey:@"stream"];
- if (stream) {
- [stream close];
- }
- [persistentConnectionsPool removeObject:existingConnection];
- i--;
- }
- }
- [connectionsLock unlock];
- }
- #pragma mark NSCopying
- - (id)copyWithZone:(NSZone *)zone
- {
-
- ASIHTTPRequest *newRequest = [[[self class] alloc] initWithURL:[self url]];
- [newRequest setDelegate:[self delegate]];
- [newRequest setRequestMethod:[self requestMethod]];
- [newRequest setPostBody:[self postBody]];
- [newRequest setShouldStreamPostDataFromDisk:[self shouldStreamPostDataFromDisk]];
- [newRequest setPostBodyFilePath:[self postBodyFilePath]];
- [newRequest setRequestHeaders:[[[self requestHeaders] mutableCopyWithZone:zone] autorelease]];
- [newRequest setRequestCookies:[[[self requestCookies] mutableCopyWithZone:zone] autorelease]];
- [newRequest setUseCookiePersistence:[self useCookiePersistence]];
- [newRequest setUseKeychainPersistence:[self useKeychainPersistence]];
- [newRequest setUseSessionPersistence:[self useSessionPersistence]];
- [newRequest setAllowCompressedResponse:[self allowCompressedResponse]];
- [newRequest setDownloadDestinationPath:[self downloadDestinationPath]];
- [newRequest setTemporaryFileDownloadPath:[self temporaryFileDownloadPath]];
- [newRequest setUsername:[self username]];
- [newRequest setPassword:[self password]];
- [newRequest setDomain:[self domain]];
- [newRequest setProxyUsername:[self proxyUsername]];
- [newRequest setProxyPassword:[self proxyPassword]];
- [newRequest setProxyDomain:[self proxyDomain]];
- [newRequest setProxyHost:[self proxyHost]];
- [newRequest setProxyPort:[self proxyPort]];
- [newRequest setProxyType:[self proxyType]];
- [newRequest setUploadProgressDelegate:[self uploadProgressDelegate]];
- [newRequest setDownloadProgressDelegate:[self downloadProgressDelegate]];
- [newRequest setShouldPresentAuthenticationDialog:[self shouldPresentAuthenticationDialog]];
- [newRequest setShouldPresentProxyAuthenticationDialog:[self shouldPresentProxyAuthenticationDialog]];
- [newRequest setPostLength:[self postLength]];
- [newRequest setHaveBuiltPostBody:[self haveBuiltPostBody]];
- [newRequest setDidStartSelector:[self didStartSelector]];
- [newRequest setDidFinishSelector:[self didFinishSelector]];
- [newRequest setDidFailSelector:[self didFailSelector]];
- [newRequest setTimeOutSeconds:[self timeOutSeconds]];
- [newRequest setShouldResetDownloadProgress:[self shouldResetDownloadProgress]];
- [newRequest setShouldResetUploadProgress:[self shouldResetUploadProgress]];
- [newRequest setShowAccurateProgress:[self showAccurateProgress]];
- [newRequest setDefaultResponseEncoding:[self defaultResponseEncoding]];
- [newRequest setAllowResumeForFileDownloads:[self allowResumeForFileDownloads]];
- [newRequest setUserInfo:[[[self userInfo] copyWithZone:zone] autorelease]];
- [newRequest setTag:[self tag]];
- [newRequest setUseHTTPVersionOne:[self useHTTPVersionOne]];
- [newRequest setShouldRedirect:[self shouldRedirect]];
- [newRequest setValidatesSecureCertificate:[self validatesSecureCertificate]];
- [newRequest setClientCertificateIdentity:clientCertificateIdentity];
- [newRequest setClientCertificates:[[clientCertificates copy] autorelease]];
- [newRequest setPACurl:[self PACurl]];
- [newRequest setShouldPresentCredentialsBeforeChallenge:[self shouldPresentCredentialsBeforeChallenge]];
- [newRequest setNumberOfTimesToRetryOnTimeout:[self numberOfTimesToRetryOnTimeout]];
- [newRequest setShouldUseRFC2616RedirectBehaviour:[self shouldUseRFC2616RedirectBehaviour]];
- [newRequest setShouldAttemptPersistentConnection:[self shouldAttemptPersistentConnection]];
- [newRequest setPersistentConnectionTimeoutSeconds:[self persistentConnectionTimeoutSeconds]];
- [newRequest setAuthenticationScheme:[self authenticationScheme]];
- return newRequest;
- }
- #pragma mark default time out
- + (NSTimeInterval)defaultTimeOutSeconds
- {
- return defaultTimeOutSeconds;
- }
- + (void)setDefaultTimeOutSeconds:(NSTimeInterval)newTimeOutSeconds
- {
- defaultTimeOutSeconds = newTimeOutSeconds;
- }
- #pragma mark client certificate
- - (void)setClientCertificateIdentity:(SecIdentityRef)anIdentity {
- if(clientCertificateIdentity) {
- CFRelease(clientCertificateIdentity);
- }
-
- clientCertificateIdentity = anIdentity;
-
- if (clientCertificateIdentity) {
- CFRetain(clientCertificateIdentity);
- }
- }
- #pragma mark session credentials
- + (NSMutableArray *)sessionProxyCredentialsStore
- {
- [sessionCredentialsLock lock];
- if (!sessionProxyCredentialsStore) {
- sessionProxyCredentialsStore = [[NSMutableArray alloc] init];
- }
- [sessionCredentialsLock unlock];
- return sessionProxyCredentialsStore;
- }
- + (NSMutableArray *)sessionCredentialsStore
- {
- [sessionCredentialsLock lock];
- if (!sessionCredentialsStore) {
- sessionCredentialsStore = [[NSMutableArray alloc] init];
- }
- [sessionCredentialsLock unlock];
- return sessionCredentialsStore;
- }
- + (void)storeProxyAuthenticationCredentialsInSessionStore:(NSDictionary *)credentials
- {
- [sessionCredentialsLock lock];
- [self removeProxyAuthenticationCredentialsFromSessionStore:[credentials objectForKey:@"Credentials"]];
- [[[self class] sessionProxyCredentialsStore] addObject:credentials];
- [sessionCredentialsLock unlock];
- }
- + (void)storeAuthenticationCredentialsInSessionStore:(NSDictionary *)credentials
- {
- [sessionCredentialsLock lock];
- [self removeAuthenticationCredentialsFromSessionStore:[credentials objectForKey:@"Credentials"]];
- [[[self class] sessionCredentialsStore] addObject:credentials];
- [sessionCredentialsLock unlock];
- }
- + (void)removeProxyAuthenticationCredentialsFromSessionStore:(NSDictionary *)credentials
- {
- [sessionCredentialsLock lock];
- NSMutableArray *sessionCredentialsList = [[self class] sessionProxyCredentialsStore];
- NSUInteger i;
- for (i=0; i<[sessionCredentialsList count]; i++) {
- NSDictionary *theCredentials = [sessionCredentialsList objectAtIndex:i];
- if ([theCredentials objectForKey:@"Credentials"] == credentials) {
- [sessionCredentialsList removeObjectAtIndex:i];
- [sessionCredentialsLock unlock];
- return;
- }
- }
- [sessionCredentialsLock unlock];
- }
- + (void)removeAuthenticationCredentialsFromSessionStore:(NSDictionary *)credentials
- {
- [sessionCredentialsLock lock];
- NSMutableArray *sessionCredentialsList = [[self class] sessionCredentialsStore];
- NSUInteger i;
- for (i=0; i<[sessionCredentialsList count]; i++) {
- NSDictionary *theCredentials = [sessionCredentialsList objectAtIndex:i];
- if ([theCredentials objectForKey:@"Credentials"] == credentials) {
- [sessionCredentialsList removeObjectAtIndex:i];
- [sessionCredentialsLock unlock];
- return;
- }
- }
- [sessionCredentialsLock unlock];
- }
- - (NSDictionary *)findSessionProxyAuthenticationCredentials
- {
- [sessionCredentialsLock lock];
- NSMutableArray *sessionCredentialsList = [[self class] sessionProxyCredentialsStore];
- for (NSDictionary *theCredentials in sessionCredentialsList) {
- if ([[theCredentials objectForKey:@"Host"] isEqualToString:[self proxyHost]] && [[theCredentials objectForKey:@"Port"] intValue] == [self proxyPort]) {
- [sessionCredentialsLock unlock];
- return theCredentials;
- }
- }
- [sessionCredentialsLock unlock];
- return nil;
- }
- - (NSDictionary *)findSessionAuthenticationCredentials
- {
- [sessionCredentialsLock lock];
- NSMutableArray *sessionCredentialsList = [[self class] sessionCredentialsStore];
- NSURL *requestURL = [self url];
- BOOL haveFoundExactMatch;
- NSDictionary *closeMatch = nil;
-
- for (NSDictionary *theCredentials in sessionCredentialsList) {
-
- haveFoundExactMatch = NO;
- NSURL *cachedCredentialsURL = [theCredentials objectForKey:@"URL"];
-
- if ([cachedCredentialsURL isEqual:[self url]]) {
- haveFoundExactMatch = YES;
-
- } else if (closeMatch) {
- continue;
-
- } else if ([[cachedCredentialsURL host] isEqualToString:[requestURL host]] && ([cachedCredentialsURL port] == [requestURL port] || ([requestURL port] && [[cachedCredentialsURL port] isEqualToNumber:[requestURL port]])) && [[cachedCredentialsURL scheme] isEqualToString:[requestURL scheme]]) {
- } else {
- continue;
- }
-
- if ([self authenticationRealm] && ([theCredentials objectForKey:@"AuthenticationRealm"] && ![[theCredentials objectForKey:@"AuthenticationRealm"] isEqualToString:[self authenticationRealm]])) {
- continue;
- }
-
- if ([self username] && [self password]) {
- NSDictionary *usernameAndPassword = [theCredentials objectForKey:@"Credentials"];
- NSString *storedUsername = [usernameAndPassword objectForKey:(NSString *)kCFHTTPAuthenticationUsername];
- NSString *storedPassword = [usernameAndPassword objectForKey:(NSString *)kCFHTTPAuthenticationPassword];
- if (![storedUsername isEqualToString:[self username]] || ![storedPassword isEqualToString:[self password]]) {
- continue;
- }
- }
-
- if (haveFoundExactMatch) {
- [sessionCredentialsLock unlock];
- return theCredentials;
- }
-
- closeMatch = theCredentials;
- }
- [sessionCredentialsLock unlock];
-
- return closeMatch;
- }
- #pragma mark keychain storage
- + (void)saveCredentials:(NSURLCredential *)credentials forHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm
- {
- NSURLProtectionSpace *protectionSpace = [[[NSURLProtectionSpace alloc] initWithHost:host port:port protocol:protocol realm:realm authenticationMethod:NSURLAuthenticationMethodDefault] autorelease];
- [[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credentials forProtectionSpace:protectionSpace];
- }
- + (void)saveCredentials:(NSURLCredential *)credentials forProxy:(NSString *)host port:(int)port realm:(NSString *)realm
- {
- NSURLProtectionSpace *protectionSpace = [[[NSURLProtectionSpace alloc] initWithProxyHost:host port:port type:NSURLProtectionSpaceHTTPProxy realm:realm authenticationMethod:NSURLAuthenticationMethodDefault] autorelease];
- [[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credentials forProtectionSpace:protectionSpace];
- }
- + (NSURLCredential *)savedCredentialsForHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm
- {
- NSURLProtectionSpace *protectionSpace = [[[NSURLProtectionSpace alloc] initWithHost:host port:port protocol:protocol realm:realm authenticationMethod:NSURLAuthenticationMethodDefault] autorelease];
- return [[NSURLCredentialStorage sharedCredentialStorage] defaultCredentialForProtectionSpace:protectionSpace];
- }
- + (NSURLCredential *)savedCredentialsForProxy:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm
- {
- NSURLProtectionSpace *protectionSpace = [[[NSURLProtectionSpace alloc] initWithProxyHost:host port:port type:NSURLProtectionSpaceHTTPProxy realm:realm authenticationMethod:NSURLAuthenticationMethodDefault] autorelease];
- return [[NSURLCredentialStorage sharedCredentialStorage] defaultCredentialForProtectionSpace:protectionSpace];
- }
- + (void)removeCredentialsForHost:(NSString *)host port:(int)port protocol:(NSString *)protocol realm:(NSString *)realm
- {
- NSURLProtectionSpace *protectionSpace = [[[NSURLProtectionSpace alloc] initWithHost:host port:port protocol:protocol realm:realm authenticationMethod:NSURLAuthenticationMethodDefault] autorelease];
- NSURLCredential *credential = [[NSURLCredentialStorage sharedCredentialStorage] defaultCredentialForProtectionSpace:protectionSpace];
- if (credential) {
- [[NSURLCredentialStorage sharedCredentialStorage] removeCredential:credential forProtectionSpace:protectionSpace];
- }
- }
- + (void)removeCredentialsForProxy:(NSString *)host port:(int)port realm:(NSString *)realm
- {
- NSURLProtectionSpace *protectionSpace = [[[NSURLProtectionSpace alloc] initWithProxyHost:host port:port type:NSURLProtectionSpaceHTTPProxy realm:realm authenticationMethod:NSURLAuthenticationMethodDefault] autorelease];
- NSURLCredential *credential = [[NSURLCredentialStorage sharedCredentialStorage] defaultCredentialForProtectionSpace:protectionSpace];
- if (credential) {
- [[NSURLCredentialStorage sharedCredentialStorage] removeCredential:credential forProtectionSpace:protectionSpace];
- }
- }
- + (NSMutableArray *)sessionCookies
- {
- [sessionCookiesLock lock];
- if (!sessionCookies) {
- [ASIHTTPRequest setSessionCookies:[NSMutableArray array]];
- }
- NSMutableArray *cookies = [[sessionCookies retain] autorelease];
- [sessionCookiesLock unlock];
- return cookies;
- }
- + (void)setSessionCookies:(NSMutableArray *)newSessionCookies
- {
- [sessionCookiesLock lock];
-
- for (NSHTTPCookie *cookie in sessionCookies) {
- [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
- }
- [sessionCookies release];
- sessionCookies = [newSessionCookies retain];
- [sessionCookiesLock unlock];
- }
- + (void)addSessionCookie:(NSHTTPCookie *)newCookie
- {
- [sessionCookiesLock lock];
- NSHTTPCookie *cookie;
- NSUInteger i;
- NSUInteger max = [[ASIHTTPRequest sessionCookies] count];
- for (i=0; i<max; i++) {
- cookie = [[ASIHTTPRequest sessionCookies] objectAtIndex:i];
- if ([[cookie domain] isEqualToString:[newCookie domain]] && [[cookie path] isEqualToString:[newCookie path]] && [[cookie name] isEqualToString:[newCookie name]]) {
- [[ASIHTTPRequest sessionCookies] removeObjectAtIndex:i];
- break;
- }
- }
- [[ASIHTTPRequest sessionCookies] addObject:newCookie];
- [sessionCookiesLock unlock];
- }
- + (void)clearSession
- {
- [sessionCredentialsLock lock];
- [[[self class] sessionCredentialsStore] removeAllObjects];
- [sessionCredentialsLock unlock];
- [[self class] setSessionCookies:nil];
- [[[self class] defaultCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
- }
- #pragma mark get user agent
- + (NSString *)defaultUserAgentString
- {
- @synchronized (self) {
- if (!defaultUserAgent) {
- NSBundle *bundle = [NSBundle bundleForClass:[self class]];
-
- NSString *appName = [bundle objectForInfoDictionaryKey:@"CFBundleDisplayName"];
- if (!appName) {
- appName = [bundle objectForInfoDictionaryKey:@"CFBundleName"];
- }
- NSData *latin1Data = [appName dataUsingEncoding:NSUTF8StringEncoding];
- appName = [[[NSString alloc] initWithData:latin1Data encoding:NSISOLatin1StringEncoding] autorelease];
-
- if (!appName) {
- return nil;
- }
- NSString *appVersion = nil;
- NSString *marketingVersionNumber = [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
- NSString *developmentVersionNumber = [bundle objectForInfoDictionaryKey:@"CFBundleVersion"];
- if (marketingVersionNumber && developmentVersionNumber) {
- if ([marketingVersionNumber isEqualToString:developmentVersionNumber]) {
- appVersion = marketingVersionNumber;
- } else {
- appVersion = [NSString stringWithFormat:@"%@ rv:%@",marketingVersionNumber,developmentVersionNumber];
- }
- } else {
- appVersion = (marketingVersionNumber ? marketingVersionNumber : developmentVersionNumber);
- }
- NSString *deviceName;
- NSString *OSName;
- NSString *OSVersion;
- NSString *locale = [[NSLocale currentLocale] localeIdentifier];
- #if TARGET_OS_IPHONE
- UIDevice *device = [UIDevice currentDevice];
- deviceName = [device model];
- OSName = [device systemName];
- OSVersion = [device systemVersion];
- #else
- deviceName = @"Macintosh";
- OSName = @"Mac OS X";
-
-
- OSErr err;
- SInt32 versionMajor, versionMinor, versionBugFix;
- err = Gestalt(gestaltSystemVersionMajor, &versionMajor);
- if (err != noErr) return nil;
- err = Gestalt(gestaltSystemVersionMinor, &versionMinor);
- if (err != noErr) return nil;
- err = Gestalt(gestaltSystemVersionBugFix, &versionBugFix);
- if (err != noErr) return nil;
- OSVersion = [NSString stringWithFormat:@"%u.%u.%u", versionMajor, versionMinor, versionBugFix];
- #endif
-
- [self setDefaultUserAgentString:[NSString stringWithFormat:@"%@ %@ (%@; %@ %@; %@)", appName, appVersion, deviceName, OSName, OSVersion, locale]];
- }
- return [[defaultUserAgent retain] autorelease];
- }
- return nil;
- }
- + (void)setDefaultUserAgentString:(NSString *)agent
- {
- @synchronized (self) {
- if (defaultUserAgent == agent) {
- return;
- }
- [defaultUserAgent release];
- defaultUserAgent = [agent copy];
- }
- }
- #pragma mark mime-type detection
- + (NSString *)mimeTypeForFileAtPath:(NSString *)path
- {
- if (![[[[NSFileManager alloc] init] autorelease] fileExistsAtPath:path]) {
- return nil;
- }
-
- CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)[path pathExtension], NULL);
- CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
- CFRelease(UTI);
- if (!MIMEType) {
- return @"application/octet-stream";
- }
- return [NSMakeCollectable(MIMEType) autorelease];
- }
- #pragma mark bandwidth measurement / throttling
- - (void)performThrottling
- {
- if (![self readStream]) {
- return;
- }
- [ASIHTTPRequest measureBandwidthUsage];
- if ([ASIHTTPRequest isBandwidthThrottled]) {
- [bandwidthThrottlingLock lock];
-
- if (throttleWakeUpTime) {
- if ([throttleWakeUpTime timeIntervalSinceDate:[NSDate date]] > 0) {
- if ([self readStreamIsScheduled]) {
- [self unscheduleReadStream];
- #if DEBUG_THROTTLING
- ASI_DEBUG_LOG(@"[THROTTLING] Sleeping request %@ until after %@",self,throttleWakeUpTime);
- #endif
- }
- } else {
- if (![self readStreamIsScheduled]) {
- [self scheduleReadStream];
- #if DEBUG_THROTTLING
- ASI_DEBUG_LOG(@"[THROTTLING] Waking up request %@",self);
- #endif
- }
- }
- }
- [bandwidthThrottlingLock unlock];
-
-
- } else if (![self readStreamIsScheduled]) {
- [self scheduleReadStream];
- }
- }
- + (BOOL)isBandwidthThrottled
- {
- #if TARGET_OS_IPHONE
- [bandwidthThrottlingLock lock];
- BOOL throttle = isBandwidthThrottled || (!shouldThrottleBandwidthForWWANOnly && (maxBandwidthPerSecond > 0));
- [bandwidthThrottlingLock unlock];
- return throttle;
- #else
- [bandwidthThrottlingLock lock];
- BOOL throttle = (maxBandwidthPerSecond > 0);
- [bandwidthThrottlingLock unlock];
- return throttle;
- #endif
- }
- + (unsigned long)maxBandwidthPerSecond
- {
- [bandwidthThrottlingLock lock];
- unsigned long amount = maxBandwidthPerSecond;
- [bandwidthThrottlingLock unlock];
- return amount;
- }
- + (void)setMaxBandwidthPerSecond:(unsigned long)bytes
- {
- [bandwidthThrottlingLock lock];
- maxBandwidthPerSecond = bytes;
- [bandwidthThrottlingLock unlock];
- }
- + (void)incrementBandwidthUsedInLastSecond:(unsigned long)bytes
- {
- [bandwidthThrottlingLock lock];
- bandwidthUsedInLastSecond += bytes;
- [bandwidthThrottlingLock unlock];
- }
- + (void)recordBandwidthUsage
- {
- if (bandwidthUsedInLastSecond == 0) {
- [bandwidthUsageTracker removeAllObjects];
- } else {
- NSTimeInterval interval = [bandwidthMeasurementDate timeIntervalSinceNow];
- while ((interval < 0 || [bandwidthUsageTracker count] > 5) && [bandwidthUsageTracker count] > 0) {
- [bandwidthUsageTracker removeObjectAtIndex:0];
- interval++;
- }
- }
- #if DEBUG_THROTTLING
- ASI_DEBUG_LOG(@"[THROTTLING] ===Used: %u bytes of bandwidth in last measurement period===",bandwidthUsedInLastSecond);
- #endif
- [bandwidthUsageTracker addObject:[NSNumber numberWithUnsignedLong:bandwidthUsedInLastSecond]];
- [bandwidthMeasurementDate release];
- bandwidthMeasurementDate = [[NSDate dateWithTimeIntervalSinceNow:1] retain];
- bandwidthUsedInLastSecond = 0;
-
- NSUInteger measurements = [bandwidthUsageTracker count];
- unsigned long totalBytes = 0;
- for (NSNumber *bytes in bandwidthUsageTracker) {
- totalBytes += [bytes unsignedLongValue];
- }
- if (measurements > 0)
- averageBandwidthUsedPerSecond = totalBytes/measurements;
- }
- + (unsigned long)averageBandwidthUsedPerSecond
- {
- [bandwidthThrottlingLock lock];
- unsigned long amount = averageBandwidthUsedPerSecond;
- [bandwidthThrottlingLock unlock];
- return amount;
- }
- + (void)measureBandwidthUsage
- {
-
- [bandwidthThrottlingLock lock];
- if (!bandwidthMeasurementDate || [bandwidthMeasurementDate timeIntervalSinceNow] < -0) {
- [ASIHTTPRequest recordBandwidthUsage];
- }
-
-
- if (
- #if TARGET_OS_IPHONE
- isBandwidthThrottled || (!shouldThrottleBandwidthForWWANOnly && (maxBandwidthPerSecond))
- #else
- maxBandwidthPerSecond
- #endif
- ) {
-
- long long bytesRemaining = (long long)maxBandwidthPerSecond - (long long)bandwidthUsedInLastSecond;
-
-
- if (bytesRemaining < 0) {
-
-
- double extraSleepyTime = (-bytesRemaining/(maxBandwidthPerSecond*1.0));
- [throttleWakeUpTime release];
- throttleWakeUpTime = [[NSDate alloc] initWithTimeInterval:extraSleepyTime sinceDate:bandwidthMeasurementDate];
- }
- }
- [bandwidthThrottlingLock unlock];
- }
-
- + (unsigned long)maxUploadReadLength
- {
- [bandwidthThrottlingLock lock];
-
-
- long long toRead = maxBandwidthPerSecond/4;
- if (maxBandwidthPerSecond > 0 && (bandwidthUsedInLastSecond + toRead > maxBandwidthPerSecond)) {
- toRead = (long long)maxBandwidthPerSecond-(long long)bandwidthUsedInLastSecond;
- if (toRead < 0) {
- toRead = 0;
- }
- }
-
- if (toRead == 0 || !bandwidthMeasurementDate || [bandwidthMeasurementDate timeIntervalSinceNow] < -0) {
- [throttleWakeUpTime release];
- throttleWakeUpTime = [bandwidthMeasurementDate retain];
- }
- [bandwidthThrottlingLock unlock];
- return (unsigned long)toRead;
- }
-
- #if TARGET_OS_IPHONE
- + (void)setShouldThrottleBandwidthForWWAN:(BOOL)throttle
- {
- if (throttle) {
- [ASIHTTPRequest throttleBandwidthForWWANUsingLimit:ASIWWANBandwidthThrottleAmount];
- } else {
- [ASIHTTPRequest unsubscribeFromNetworkReachabilityNotifications];
- [ASIHTTPRequest setMaxBandwidthPerSecond:0];
- [bandwidthThrottlingLock lock];
- isBandwidthThrottled = NO;
- shouldThrottleBandwidthForWWANOnly = NO;
- [bandwidthThrottlingLock unlock];
- }
- }
- + (void)throttleBandwidthForWWANUsingLimit:(unsigned long)limit
- {
- [bandwidthThrottlingLock lock];
- shouldThrottleBandwidthForWWANOnly = YES;
- maxBandwidthPerSecond = limit;
- [ASIHTTPRequest registerForNetworkReachabilityNotifications];
- [bandwidthThrottlingLock unlock];
- [ASIHTTPRequest reachabilityChanged:nil];
- }
- #pragma mark reachability
- + (void)registerForNetworkReachabilityNotifications
- {
- [[Reachability reachabilityForInternetConnection] startNotifier];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
- }
- + (void)unsubscribeFromNetworkReachabilityNotifications
- {
- [[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil];
- }
- + (BOOL)isNetworkReachableViaWWAN
- {
- return ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] == ReachableViaWWAN);
- }
- + (void)reachabilityChanged:(NSNotification *)note
- {
- [bandwidthThrottlingLock lock];
- isBandwidthThrottled = [ASIHTTPRequest isNetworkReachableViaWWAN];
- [bandwidthThrottlingLock unlock];
- }
- #endif
- #pragma mark queue
- + (NSOperationQueue *)sharedQueue
- {
- return [[sharedQueue retain] autorelease];
- }
- #pragma mark cache
- + (void)setDefaultCache:(id <ASICacheDelegate>)cache
- {
- @synchronized (self) {
- [cache retain];
- [defaultCache release];
- defaultCache = cache;
- }
- }
- + (id <ASICacheDelegate>)defaultCache
- {
- @synchronized(self) {
- return [[defaultCache retain] autorelease];
- }
- return nil;
- }
- #pragma mark network activity
- + (BOOL)isNetworkInUse
- {
- [connectionsLock lock];
- BOOL inUse = (runningRequestCount > 0);
- [connectionsLock unlock];
- return inUse;
- }
- + (void)setShouldUpdateNetworkActivityIndicator:(BOOL)shouldUpdate
- {
- [connectionsLock lock];
- shouldUpdateNetworkActivityIndicator = shouldUpdate;
- [connectionsLock unlock];
- }
- + (void)showNetworkActivityIndicator
- {
- #if TARGET_OS_IPHONE
- [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
- #endif
- }
- + (void)hideNetworkActivityIndicator
- {
- #if TARGET_OS_IPHONE
- [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
- #endif
- }
- + (void)hideNetworkActivityIndicatorAfterDelay
- {
- [self performSelector:@selector(hideNetworkActivityIndicatorIfNeeeded) withObject:nil afterDelay:0.5];
- }
- + (void)hideNetworkActivityIndicatorIfNeeeded
- {
- [connectionsLock lock];
- if (runningRequestCount == 0) {
- [self hideNetworkActivityIndicator];
- }
- [connectionsLock unlock];
- }
- #pragma mark threading behaviour
- + (NSThread *)threadForRequest:(ASIHTTPRequest *)request
- {
- if (networkThread == nil) {
- @synchronized(self) {
- if (networkThread == nil) {
- networkThread = [[NSThread alloc] initWithTarget:self selector:@selector(runRequests) object:nil];
- [networkThread start];
- }
- }
- }
- return networkThread;
- }
- + (void)runRequests
- {
-
- CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
- CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
- BOOL runAlways = YES;
- while (runAlways) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
- [pool drain];
- }
-
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
- CFRelease(source);
- }
- #pragma mark miscellany
- #if TARGET_OS_IPHONE
- + (BOOL)isMultitaskingSupported
- {
- BOOL multiTaskingSupported = NO;
- if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)]) {
- multiTaskingSupported = [(id)[UIDevice currentDevice] isMultitaskingSupported];
- }
- return multiTaskingSupported;
- }
- #endif
- + (NSString*)base64forData:(NSData*)theData {
-
- const uint8_t* input = (const uint8_t*)[theData bytes];
- NSUInteger length = [theData length];
-
- static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
-
- NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
- uint8_t* output = (uint8_t*)data.mutableBytes;
-
- NSUInteger i,i2;
- for (i=0; i < length; i += 3) {
- NSInteger value = 0;
- for (i2=0; i2<3; i2++) {
- value <<= 8;
- if (i+i2 < length) {
- value |= (0xFF & input[i+i2]);
- }
- }
-
- NSInteger theIndex = (i / 3) * 4;
- output[theIndex + 0] = (uint8_t)table[(value >> 18) & 0x3F];
- output[theIndex + 1] = (uint8_t)table[(value >> 12) & 0x3F];
- output[theIndex + 2] = (i + 1) < length ? (uint8_t)table[(value >> 6) & 0x3F] : '=';
- output[theIndex + 3] = (i + 2) < length ? (uint8_t)table[(value >> 0) & 0x3F] : '=';
- }
-
- return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
- }
- + (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
- {
- NSDictionary *responseHeaders = [request responseHeaders];
-
-
- if (!maxAge) {
- NSString *cacheControl = [[responseHeaders objectForKey:@"Cache-Control"] lowercaseString];
- if (cacheControl) {
- NSScanner *scanner = [NSScanner scannerWithString:cacheControl];
- [scanner scanUpToString:@"max-age" intoString:NULL];
- if ([scanner scanString:@"max-age" intoString:NULL]) {
- [scanner scanString:@"=" intoString:NULL];
- [scanner scanDouble:&maxAge];
- }
- }
- }
-
-
- if (maxAge) {
- NSDate *date = [NSDate date];
- if ([date respondsToSelector:@selector(dateByAddingTimeInterval:)]) {
- return [date dateByAddingTimeInterval:maxAge];
- } else {
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- return [date addTimeInterval:maxAge];
- #pragma clang diagnostic pop
- }
- } else {
- NSString *expires = [responseHeaders objectForKey:@"Expires"];
- if (expires) {
- return [ASIHTTPRequest dateFromRFC1123String:expires];
- }
- }
- return nil;
- }
- + (NSDate *)dateFromRFC1123String:(NSString *)string
- {
- NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
- [formatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
-
- NSString *day = @"";
- if ([string rangeOfString:@","].location != NSNotFound) {
- day = @"EEE, ";
- }
-
- NSString *seconds = @"";
- if ([[string componentsSeparatedByString:@":"] count] == 3) {
- seconds = @":ss";
- }
- [formatter setDateFormat:[NSString stringWithFormat:@"%@dd MMM yyyy HH:mm%@ z",day,seconds]];
- return [formatter dateFromString:string];
- }
- + (void)parseMimeType:(NSString **)mimeType andResponseEncoding:(NSStringEncoding *)stringEncoding fromContentType:(NSString *)contentType
- {
- if (!contentType) {
- return;
- }
- NSScanner *charsetScanner = [NSScanner scannerWithString: contentType];
- if (![charsetScanner scanUpToString:@";" intoString:mimeType] || [charsetScanner scanLocation] == [contentType length]) {
- *mimeType = [contentType stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
- return;
- }
- *mimeType = [*mimeType stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
- NSString *charsetSeparator = @"charset=";
- NSString *IANAEncoding = nil;
- if ([charsetScanner scanUpToString: charsetSeparator intoString: NULL] && [charsetScanner scanLocation] < [contentType length]) {
- [charsetScanner setScanLocation: [charsetScanner scanLocation] + [charsetSeparator length]];
- [charsetScanner scanUpToString: @";" intoString: &IANAEncoding];
- }
- if (IANAEncoding) {
- CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)IANAEncoding);
- if (cfEncoding != kCFStringEncodingInvalidId) {
- *stringEncoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
- }
- }
- }
- #pragma mark -
- #pragma mark blocks
- #if NS_BLOCKS_AVAILABLE
- - (void)setStartedBlock:(ASIBasicBlock)aStartedBlock
- {
- [startedBlock release];
- startedBlock = [aStartedBlock copy];
- }
- - (void)setHeadersReceivedBlock:(ASIHeadersBlock)aReceivedBlock
- {
- [headersReceivedBlock release];
- headersReceivedBlock = [aReceivedBlock copy];
- }
- - (void)setCompletionBlock:(ASIBasicBlock)aCompletionBlock
- {
- [completionBlock release];
- completionBlock = [aCompletionBlock copy];
- }
- - (void)setFailedBlock:(ASIBasicBlock)aFailedBlock
- {
- [failureBlock release];
- failureBlock = [aFailedBlock copy];
- }
- - (void)setBytesReceivedBlock:(ASIProgressBlock)aBytesReceivedBlock
- {
- [bytesReceivedBlock release];
- bytesReceivedBlock = [aBytesReceivedBlock copy];
- }
- - (void)setBytesSentBlock:(ASIProgressBlock)aBytesSentBlock
- {
- [bytesSentBlock release];
- bytesSentBlock = [aBytesSentBlock copy];
- }
- - (void)setDownloadSizeIncrementedBlock:(ASISizeBlock)aDownloadSizeIncrementedBlock{
- [downloadSizeIncrementedBlock release];
- downloadSizeIncrementedBlock = [aDownloadSizeIncrementedBlock copy];
- }
- - (void)setUploadSizeIncrementedBlock:(ASISizeBlock)anUploadSizeIncrementedBlock
- {
- [uploadSizeIncrementedBlock release];
- uploadSizeIncrementedBlock = [anUploadSizeIncrementedBlock copy];
- }
- - (void)setDataReceivedBlock:(ASIDataBlock)aReceivedBlock
- {
- [dataReceivedBlock release];
- dataReceivedBlock = [aReceivedBlock copy];
- }
- - (void)setAuthenticationNeededBlock:(ASIBasicBlock)anAuthenticationBlock
- {
- [authenticationNeededBlock release];
- authenticationNeededBlock = [anAuthenticationBlock copy];
- }
- - (void)setProxyAuthenticationNeededBlock:(ASIBasicBlock)aProxyAuthenticationBlock
- {
- [proxyAuthenticationNeededBlock release];
- proxyAuthenticationNeededBlock = [aProxyAuthenticationBlock copy];
- }
- - (void)setRequestRedirectedBlock:(ASIBasicBlock)aRedirectBlock
- {
- [requestRedirectedBlock release];
- requestRedirectedBlock = [aRedirectBlock copy];
- }
- #endif
- #pragma mark ===
- @synthesize username;
- @synthesize password;
- @synthesize userAgentString;
- @synthesize domain;
- @synthesize proxyUsername;
- @synthesize proxyPassword;
- @synthesize proxyDomain;
- @synthesize url;
- @synthesize originalURL;
- @synthesize delegate;
- @synthesize queue;
- @synthesize uploadProgressDelegate;
- @synthesize downloadProgressDelegate;
- @synthesize useKeychainPersistence;
- @synthesize useSessionPersistence;
- @synthesize useCookiePersistence;
- @synthesize downloadDestinationPath;
- @synthesize temporaryFileDownloadPath;
- @synthesize temporaryUncompressedDataDownloadPath;
- @synthesize didStartSelector;
- @synthesize didReceiveResponseHeadersSelector;
- @synthesize willRedirectSelector;
- @synthesize didFinishSelector;
- @synthesize didFailSelector;
- @synthesize didReceiveDataSelector;
- @synthesize authenticationRealm;
- @synthesize proxyAuthenticationRealm;
- @synthesize error;
- @synthesize complete;
- @synthesize requestHeaders;
- @synthesize responseHeaders;
- @synthesize responseCookies;
- @synthesize requestCookies;
- @synthesize requestCredentials;
- @synthesize responseStatusCode;
- @synthesize rawResponseData;
- @synthesize lastActivityTime;
- @synthesize timeOutSeconds;
- @synthesize requestMethod;
- @synthesize postBody;
- @synthesize compressedPostBody;
- @synthesize contentLength;
- @synthesize partialDownloadSize;
- @synthesize postLength;
- @synthesize shouldResetDownloadProgress;
- @synthesize shouldResetUploadProgress;
- @synthesize mainRequest;
- @synthesize totalBytesRead;
- @synthesize totalBytesSent;
- @synthesize showAccurateProgress;
- @synthesize uploadBufferSize;
- @synthesize defaultResponseEncoding;
- @synthesize responseEncoding;
- @synthesize allowCompressedResponse;
- @synthesize allowResumeForFileDownloads;
- @synthesize userInfo;
- @synthesize tag;
- @synthesize postBodyFilePath;
- @synthesize compressedPostBodyFilePath;
- @synthesize postBodyWriteStream;
- @synthesize postBodyReadStream;
- @synthesize shouldStreamPostDataFromDisk;
- @synthesize didCreateTemporaryPostDataFile;
- @synthesize useHTTPVersionOne;
- @synthesize lastBytesRead;
- @synthesize lastBytesSent;
- @synthesize cancelledLock;
- @synthesize haveBuiltPostBody;
- @synthesize fileDownloadOutputStream;
- @synthesize inflatedFileDownloadOutputStream;
- @synthesize authenticationRetryCount;
- @synthesize proxyAuthenticationRetryCount;
- @synthesize updatedProgress;
- @synthesize shouldRedirect;
- @synthesize validatesSecureCertificate;
- @synthesize needsRedirect;
- @synthesize redirectCount;
- @synthesize shouldCompressRequestBody;
- @synthesize proxyCredentials;
- @synthesize proxyHost;
- @synthesize proxyPort;
- @synthesize proxyType;
- @synthesize PACurl;
- @synthesize authenticationScheme;
- @synthesize proxyAuthenticationScheme;
- @synthesize shouldPresentAuthenticationDialog;
- @synthesize shouldPresentProxyAuthenticationDialog;
- @synthesize authenticationNeeded;
- @synthesize responseStatusMessage;
- @synthesize shouldPresentCredentialsBeforeChallenge;
- @synthesize haveBuiltRequestHeaders;
- @synthesize inProgress;
- @synthesize numberOfTimesToRetryOnTimeout;
- @synthesize retryCount;
- @synthesize willRetryRequest;
- @synthesize shouldAttemptPersistentConnection;
- @synthesize persistentConnectionTimeoutSeconds;
- @synthesize connectionCanBeReused;
- @synthesize connectionInfo;
- @synthesize readStream;
- @synthesize readStreamIsScheduled;
- @synthesize shouldUseRFC2616RedirectBehaviour;
- @synthesize downloadComplete;
- @synthesize requestID;
- @synthesize runLoopMode;
- @synthesize statusTimer;
- @synthesize downloadCache;
- @synthesize cachePolicy;
- @synthesize cacheStoragePolicy;
- @synthesize didUseCachedResponse;
- @synthesize secondsToCache;
- @synthesize clientCertificates;
- @synthesize redirectURL;
- #if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
- @synthesize shouldContinueWhenAppEntersBackground;
- #endif
- @synthesize dataDecompressor;
- @synthesize shouldWaitToInflateCompressedResponses;
- @synthesize isPACFileRequest;
- @synthesize PACFileRequest;
- @synthesize PACFileReadStream;
- @synthesize PACFileData;
- @synthesize isSynchronous;
- @end
|