FskErr KprMessageSetResponseHeader(KprMessage self, char* name, char* value) { FskErr err = kFskErrNone; if (!self->response.headers) self->response.headers = FskAssociativeArrayNew(); if (self->response.headers) FskAssociativeArrayElementSet(self->response.headers, (const char*)name, (const char*)value, 0, kFskStringType); return err; }
void FskEnvironmentSet(const char *name, const char *value) { FskThread thread = FskThreadGetCurrent(); FskAssociativeArray vars = gEnvironment; if (!(kFskThreadFlagsIsMain & thread->flags)) { if (NULL == thread->environmentVariables) thread->environmentVariables = FskAssociativeArrayNew(); vars = thread->environmentVariables; } FskAssociativeArrayElementSetString(vars, name, (char *)value); }
// ------------------------------------------------------------------------ FskErr FskHeaderStructNew(FskHeaders **headers) { FskErr err; FskHeaders *ret; *headers = NULL; err = FskMemPtrNewClear(sizeof(FskHeaders), &ret); if (err != kFskErrNone) return err; ret->theHeaders = FskAssociativeArrayNew(); *headers = ret; return kFskErrNone; }
void KprZeroconfServiceShare(KprService self, char* authority, Boolean shareIt, Boolean useEnvironment) { FskErr err = kFskErrNone; char* type = NULL; KprZeroconfAdvertisement advertisement = NULL; KprHTTPServer server = KprHTTPServerGet(authority); bailIfError(KprZeroconfServiceNewType(authority, &type)); advertisement = KprZeroconfAdvertisementFind(gKprZeroconfAdvertisements, type, 0); if (shareIt && useEnvironment) shareIt = KprEnvironmentGetUInt32("useZeroconf", 0); if (shareIt && server) { if (!advertisement) { UInt32 port = server ? KprHTTPServerGetPort(server) : 0; Boolean secure = server ? KprHTTPServerIsSecure(server) : false; char* uuid = FskUUIDGetForKey(authority); FskAssociativeArray txt = NULL; if (secure) { txt = FskAssociativeArrayNew(); FskAssociativeArrayElementSetString(txt, "secure", "true"); } bailIfError(KprZeroconfAdvertisementNew(&advertisement, type, uuid, port, txt)); bailIfError(KprZeroconfPlatformAdvertisementStart(advertisement)); FskListAppend(&gKprZeroconfAdvertisements, advertisement); } } else { if (advertisement) { FskListRemove(&gKprZeroconfAdvertisements, advertisement); bailIfError(KprZeroconfPlatformAdvertisementStop(advertisement)); KprZeroconfAdvertisementDispose(advertisement); } } bail: if (err) KprZeroconfAdvertisementDispose(advertisement); FskMemPtrDispose(type); FskMemPtrDispose(authority); return; }
void Zeroconf_Advertisement(xsMachine *the) { KprZeroconfAdvertisement self = NULL; char* serviceType = xsToString(xsArg(0)); char* servicName = xsToString(xsArg(1)); int servicPort = xsToInteger(xsArg(2)); xsIntegerValue c = xsToInteger(xsArgc); FskAssociativeArray txt = NULL; if ((c > 3) && xsIsInstanceOf(xsArg(3), xsObjectPrototype)) { xsVars(2); xsEnterSandbox(); fxPush(xsArg(3)); fxRunForIn(the); txt = FskAssociativeArrayNew(); for (xsVar(0) = fxPop(); xsTypeOf(xsVar(0)) != xsNullType; xsVar(0) = fxPop()) { if (xsTypeOf(xsVar(0)) == xsStringType) { xsVar(1) = xsGetAt(xsArg(3), xsVar(0)); if (!xsIsInstanceOf(xsVar(1), xsObjectPrototype)) { char* name = xsToString(xsVar(0)); char* value = xsToString(xsVar(1)); FskAssociativeArrayElementSetString(txt, name, value); } } } xsLeaveSandbox(); } xsThrowIfFskErr(KprZeroconfAdvertisementNew(&self, serviceType, servicName, servicPort, txt)); xsSetHostData(xsResult, self); self->registeredCallback = Zeroconf_advertisement_registeredCallback; self->unregisteredCallback = Zeroconf_advertisement_unregisteredCallback; self->the = the; self->slot = xsResult; self->code = the->code; self->behavior = xsUndefined; xsRemember(self->slot); }
FskErr KprQueryParse(char* query, FskAssociativeArray* it) { FskErr err = kFskErrNone; FskAssociativeArray array; char *name, *decodedName; char *value, *decodedValue; char c; array = FskAssociativeArrayNew(); bailIfNULL(array); name = query; value = NULL; while ((c = *query++)) { if (c == '=') { value = query; } else if (c == '&') { if (value) *(value - 1) = 0; *(query - 1) = 0; if (kFskErrNone == KprQueryDecode(name, &decodedName)) { if (value) { if (kFskErrNone == KprQueryDecode(value, &decodedValue)) { FskAssociativeArrayElementSet(array, (const char*)decodedName, (const char*)decodedValue, 0, kFskStringType); if (decodedValue != value) FskMemPtrDispose(decodedValue); } } else FskAssociativeArrayElementSet(array, (const char*)decodedName, "", 0, kFskStringType); if (decodedName != name) FskMemPtrDispose(decodedName); } *(query - 1) = '&'; if (value) *(value - 1) = '='; name = query; value = NULL; } } if (value) *(value - 1) = 0; if (kFskErrNone == KprQueryDecode(name, &decodedName)) { if (value) { if (kFskErrNone == KprQueryDecode(value, &decodedValue)) { FskAssociativeArrayElementSet(array, (const char*)decodedName, (const char*)decodedValue, 0, kFskStringType); if (decodedValue != value) FskMemPtrDispose(decodedValue); } } else FskAssociativeArrayElementSet(array, (const char*)decodedName, "", 0, kFskStringType); if (decodedName != name) FskMemPtrDispose(decodedName); } if (value) *(value - 1) = '='; *it = array; bail: return err; }
char *FskUUIDGetForKey(const char *key) { char *uuidStr; FskUUIDRecord uuid; char *uuidCachePath = NULL, *prefFolder; FskFile fref; if (kFskErrNone == FskDirectoryGetSpecialPath(kFskDirectorySpecialTypeApplicationPreference, true, NULL, &prefFolder)) { uuidCachePath = FskStrDoCat(prefFolder, "fskuuidcache.txt"); FskMemPtrDispose(prefFolder); } // load the cache if (NULL == gUUIDCache) { char *uuidCache; FskInt64 cacheSize; gUUIDCache = FskAssociativeArrayNew(); if ((NULL != uuidCachePath) && (kFskErrNone == FskFileLoad(uuidCachePath, (unsigned char **)(void *)&uuidCache, &cacheSize))) { char *p = uuidCache; while (true) { char *uuid = p; char *mykey = FskStrChr(p, '\t'); char *cr; if (NULL == mykey) break; cr = FskStrChr(mykey, '\n'); if (NULL == cr) break; *mykey++ = 0; *cr = 0; FskAssociativeArrayElementSetString(gUUIDCache, mykey, uuid); p = cr + 1; } FskMemPtrDispose(uuidCache); } } // check the cache uuidStr = FskAssociativeArrayElementGetString(gUUIDCache, key); if (uuidStr) { FskMemPtrDispose(uuidCachePath); return uuidStr; } // not in cache FskUUIDCreate(&uuid); uuidStr = FskUUIDtoString_844412(&uuid); FskAssociativeArrayElementSetString(gUUIDCache, key, uuidStr); FskMemPtrDispose(uuidStr); // flush cache FskFileDelete(uuidCachePath); FskFileCreate(uuidCachePath); if (kFskErrNone == FskFileOpen(uuidCachePath, kFskFilePermissionReadWrite, &fref)) { FskAssociativeArrayIterator iterate = FskAssociativeArrayIteratorNew(gUUIDCache); char tab = '\t', cr = '\n'; while (iterate) { FskFileWrite(fref, FskStrLen(iterate->value), iterate->value, NULL); FskFileWrite(fref, 1, &tab, NULL); FskFileWrite(fref, FskStrLen(iterate->name), iterate->name, NULL); FskFileWrite(fref, 1, &cr, NULL); iterate = FskAssociativeArrayIteratorNext(iterate); } FskFileClose(fref); } FskMemPtrDispose(uuidCachePath); return FskAssociativeArrayElementGetString(gUUIDCache, key); // caller doesn't have to dispose }
// ------------------------------------------------------------------------ static int sParseStartLine(char *startLine, UInt16 headerType, FskHeaders *headers) { FskErr err; int l; const char *p; char *c = startLine; char *firstPart; // Get method or protocol p = c; c = FskStrChr(c, ' '); if (!c) return -1; l = (c++) - p; err = FskMemPtrNew(l+1, &firstPart); if (err != kFskErrNone) return -1; FskStrNCopy(firstPart, p, l); firstPart[l] = '\0'; if (kFskHeaderTypeResponse == headerType) headers->protocol = firstPart; else headers->method = firstPart; c = FskStrStripHeadSpace(c); // skip over space headers->headerType = headerType; if (kFskHeaderTypeResponse == headerType) { // Get response code and message (if message not in HTTP_Responses) headers->responseCode = FskStrToNum(c); if (headers->flags & kFskHeadersNonStandardResponseReasonPhrase) { c = FskStrChr(c, ' '); if (c) { char *r, *s; s = FskStrStripHeadSpace(c); r = FskFindResponse(headers->responseCode); if (!r || (0 != FskStrCompareCaseInsensitiveWithLength(s, r, FskStrLen(r)))) { headers->responseReasonPhrase = FskStrDoCopy(s); if (NULL != headers->responseReasonPhrase) FskStrStripTailSpace(headers->responseReasonPhrase); } } } } else { char *s, *t = NULL; char *uri = NULL; // Get URI if ((*c == '/') && !(headers->flags & kFskHeadersDoNotStripURILeadingSlash)) c++; s = FskStrChr(c, ' '); if (!s) { headers->responseCode = 400; return -1; } headers->protocol = FskStrDoCopy(s + 1); if (NULL != headers->protocol) FskStrStripTailSpace(headers->protocol); BAIL_IF_ERR(FskMemPtrNew((s-c)+1, &uri)); BAIL_IF_ERR(FskMemPtrNew((s-c)+1, &t)); FskMemCopy(uri, c, s-c); uri[s-c] = '\0'; s = FskStrChr(uri, '?'); if (s) *s = 0; FskStrDecodeEscapedChars(uri, t); if (s) { *s = '?'; FskStrCat(t, s); } headers->URI = FskStrDoCopy(t); // Break URI into filename and parameters s = FskStrChr(t, '?'); if (!s) { headers->filename = FskStrDoCopy(t); } else { // URI has parameters *s++ = '\0'; // cap off the filename headers->filename = FskStrDoCopy(t); headers->parameters = FskAssociativeArrayNew(); while (s) { char *name = s; char *value = FskStrChr(name, '='); if (!value) break; s = FskStrChr(value, '&'); *value++ = '\0'; // cap off the name if (s) *s++ = '\0'; // cap off the value FskAssociativeArrayElementSetString(headers->parameters, name, value); } } bail: FskMemPtrDispose(uri); FskMemPtrDispose(t); } return headers->headerType; }
FskErr FskEnvironmentInitialize(void) { char *appPath; gEnvironment = FskAssociativeArrayNew(); appPath = FskGetApplicationPath(); FskEnvironmentSet("applicationPath", appPath); FskMemPtrDispose(appPath); #if TARGET_OS_KPL KplEnvironmentInitialize(gEnvironment); #elif TARGET_OS_ANDROID FskEnvironmentSet("application", "PLAY"); #elif TARGET_OS_WIN32 || TARGET_OS_MAC || TARGET_OS_LINUX FskEnvironmentSet("application", FSK_APPLICATION); #else FskEnvironmentSet("application", "PLAY"); #endif #if TARGET_OS_WIN32 { char name[256], *nameTemp = NULL; UInt16 nameW[256]; char num[32]; DWORD nameSize = sizeof(nameW) / sizeof(UInt16); EXTENDED_NAME_FORMAT exNameFormat = NameSamCompatible; if (GetUserNameExW(exNameFormat, (LPWSTR)nameW, &nameSize)) { FskTextUnicode16LEToUTF8(nameW, nameSize * 2, &nameTemp, NULL); FskStrCopy(name, nameTemp); FskEnvironmentSet("loginName", name); FskMemPtrDispose(nameTemp); } FskEnvironmentSet("OS", "Windows"); FskStrNumToStr(gWindowsVersionInfo.dwMajorVersion, name, sizeof(name)); FskStrCat(name, "."); FskStrNumToStr(gWindowsVersionInfo.dwMinorVersion, num, sizeof(num)); FskStrCat(name, num); FskEnvironmentSet("OSVersion", name); } #elif TARGET_OS_MAC { struct utsname un; char name[256], *model; SInt32 gen; #if TARGET_OS_IPHONE FskEnvironmentSet("OS", "iPhone"); #else FskEnvironmentSet("OS", "Mac"); #endif FskCocoaSystemGetVersion(name); FskEnvironmentSet("OSVersion", name); if (uname(&un) == 0) { model = un.machine; if (FskStrCompareWithLength(model, "iPhone", 6) == 0) gen = FskStrToNum(model + 6); else if (FskStrCompareWithLength(model, "iPad", 4) == 0) { gen = FskStrToNum(model + 4); if (gen == 3) { SInt32 minor = FskStrToNum(model + 6); if (minor == 4) /* 4th gen */ gen = 5; else gen = 4; /* Only the 3rd gen iPad doesn't follow the numbering system */ } else gen += 2; } else if (FskStrCompareWithLength(model, "iPod", 4) == 0) { gen = FskStrToNum(model + 4); if (gen > 1) --gen; } else gen = 99; } else { model = "unknown"; gen = 99; } FskEnvironmentSet("Model", model); FskStrNumToStr(gen, name, sizeof(name)); FskEnvironmentSet("Generation", name); } #elif TARGET_OS_LINUX { struct utsname name; uname(&name); if (getlogin()) FskEnvironmentSet("loginName", getlogin()); else FskEnvironmentSet("loginName", "User"); FskEnvironmentSet("OS", name.sysname); FskEnvironmentSet("OSVersion", name.release); //@@ } #endif return kFskErrNone; }
Boolean KprHTTPClientPutTargetCache(KprHTTPTarget target) { FskErr err = kFskErrNone; char* control = NULL; KprHTTPClient self = gKprHTTPClient; KprMessage message = target->message; UInt32 date = 0; UInt32 maxAge = 0; UInt32 lifetime = 0; char* start; char* next; char* end; Boolean foundAge = false; Boolean revalidate = false; KprHTTPCacheValue cached = NULL; bailIfError(message->error || !FskStrCompareCaseInsensitiveWithLength(message->url, "https://", 8) || ((message->status != 200) && (message->status != 203)) || (message->method && FskStrCompare(message->method, "GET")) // only caching GET method || (message->user != NULL) // do not cache request with credentials || (message->password != NULL) // do not cache request with credentials || (message->response.size == 0) // only caching something || (message->response.size > 384000)); // not caching big files if ((control = KprMessageGetResponseHeader(message, kFskStrCacheControl))) { start = control; end = control + FskStrLen(control); // split while (start < end) { if (*start == ',') *start = 0; start++; } start = control; while (start <= end) { next = start + FskStrLen(start) + 1; start = FskStrStripHeadSpace(start); if (!FskStrCompareCaseInsensitiveWithLength(start, "max-age", 7)) { bailIfError(!(start = FskStrStripHeadSpace(start + 7))); bailIfError(*start != '='); bailIfError(!(start = FskStrStripHeadSpace(start + 1))); maxAge = FskStrToNum(start); foundAge = true; } else if (!FskStrCompareCaseInsensitiveWithLength(start, "no-cache", 8)) { revalidate = true; } else if (!FskStrCompareCaseInsensitiveWithLength(start, "no-store", 8)) { BAIL(kFskErrInvalidParameter); } else if (!FskStrCompareCaseInsensitiveWithLength(start, "must-revalidate", 15)) { revalidate = true; } start = next; } } KprDateFromHTTP(KprMessageGetResponseHeader(message, kprHTTPHeaderDate), &date); if (foundAge) lifetime = maxAge; else { UInt32 expire = 0; KprDateFromHTTP(KprMessageGetResponseHeader(message, kFskStrExpires), &expire); if (date && expire) lifetime = (expire > date) ? expire - date : 0; else if (!KprMessageGetResponseHeader(message, kprHTTPHeaderETag) && !KprMessageGetResponseHeader(message, kprHTTPHeaderLastModified)) BAIL(kFskErrInvalidParameter); // not cached } if (KprMessageGetResponseHeader(message, kprHTTPHeaderVary)) revalidate = true; if (!revalidate) lifetime += 180; // guess 3 minutes // put in cache // fprintf(stderr, "%p: CACHE %s for %d (%d)\n", message, message->url, lifetime, revalidate); bailIfError(KprHTTPCacheValueNew(&cached)); KprDateFromHTTP(KprMessageGetResponseHeader(message, kprHTTPHeaderAge), &cached->age); cached->date = date; cached->lifetime = lifetime; cached->requestDate = target->requestDate; cached->responseDate = target->responseDate; cached->status = message->status; cached->headers = FskAssociativeArrayNew(); { FskAssociativeArrayIterator iterate = FskAssociativeArrayIteratorNew(message->response.headers); while (iterate) { FskAssociativeArrayElementSet(cached->headers, iterate->name, iterate->value, 0, kFskStringType); iterate = FskAssociativeArrayIteratorNext(iterate); } FskAssociativeArrayIteratorDispose(iterate); } KprHTTPCacheValueCleanupHeaders(cached); cached->size = message->response.size; cached->body = message->response.body; target->cached = cached; bailIfError(KprHTTPCachePut(self->cache, message->url, cached)); bail: if (control) { // unsplit start = control; while (start < end) { if (*start == 0) *start = ','; start++; } } if (err == kFskErrNone) return true; target->cached = NULL; if (cached) KprMemPtrDispose(cached); return false; }