Skip to content

Commit e4cfd27

Browse files
mamabusiparkera
authored andcommitted
Implementation of XDG File specification and a basic implementation of HTTPCookieStorage (#889)
* Initial implementation of HTTPCookieStorage * Implementation of XDG File specification. * Included testcase for the implementation of XDG specification. * Added the file required to create the new executable. * Modified code changes to address the review comments.
1 parent adf4e24 commit e4cfd27

File tree

11 files changed

+682
-14
lines changed

11 files changed

+682
-14
lines changed

CoreFoundation/Base.subproj/CFFileUtilities.c

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <errno.h>
1616
#include <string.h>
1717
#include <stdio.h>
18+
#include <assert.h>
1819

1920
#if DEPLOYMENT_TARGET_WINDOWS
2021
#include <io.h>
@@ -1166,3 +1167,181 @@ CF_PRIVATE void _CFIterateDirectory(CFStringRef directoryPath, Boolean appendSla
11661167
#endif
11671168
}
11681169

1170+
#if DEPLOYMENT_RUNTIME_SWIFT
1171+
1172+
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
1173+
// Version 0.8
1174+
1175+
// This may not be safe to assume
1176+
#define _kCFXDGStringEncoding kCFStringEncodingUTF8
1177+
1178+
// All paths set in these environment variables must be absolute. If an implementation encounters a relative path in any of these variables it should consider the path invalid and ignore it.
1179+
static CFStringRef _CFXDGCreateHome(void) {
1180+
const char *home = __CFgetenv("HOME");
1181+
if (home && strnlen(home, CFMaxPathSize) > 0) {
1182+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, home, _kCFXDGStringEncoding);
1183+
} else {
1184+
return CFRetain(CFSTR(""));
1185+
}
1186+
}
1187+
1188+
/// a single base directory relative to which user-specific data files should be written. This directory is defined by the environment variable $XDG_DATA_HOME.
1189+
CF_SWIFT_EXPORT
1190+
CFStringRef _CFXDGCreateDataHomePath(void) {
1191+
// $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored. If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used.
1192+
const char *dataHome = __CFgetenv("XDG_DATA_HOME");
1193+
if (dataHome && strnlen(dataHome, CFMaxPathSize) > 1 && dataHome[0] == '/') {
1194+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, dataHome, _kCFXDGStringEncoding);
1195+
} else {
1196+
CFStringRef home = _CFXDGCreateHome();
1197+
CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@/.local/share"), home);
1198+
CFRelease(home);
1199+
return result;
1200+
}
1201+
}
1202+
1203+
/// a single base directory relative to which user-specific configuration files should be written. This directory is defined by the environment variable $XDG_CONFIG_HOME.
1204+
CF_SWIFT_EXPORT
1205+
CFStringRef _CFXDGCreateConfigHomePath(void) {
1206+
// $XDG_CONFIG_HOME defines the base directory relative to which user specific configuration files should be stored. If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config should be used.
1207+
const char *configHome = __CFgetenv("XDG_CONFIG_HOME");
1208+
if (configHome && strnlen(configHome, CFMaxPathSize) > 1 && configHome[0] == '/') {
1209+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, configHome, _kCFXDGStringEncoding);
1210+
} else {
1211+
CFStringRef home = _CFXDGCreateHome();
1212+
CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@/.config"), home);
1213+
CFRelease(home);
1214+
return result;
1215+
}
1216+
}
1217+
1218+
/// a set of preference ordered base directories relative to which data files should be searched. This set of directories is defined by the environment variable $XDG_DATA_DIRS.
1219+
CF_SWIFT_EXPORT
1220+
CFArrayRef _CFXDGCreateDataDirectoriesPaths(void) {
1221+
// $XDG_DATA_DIRS defines the preference-ordered set of base directories to search for data files in addition to the $XDG_DATA_HOME base directory. The directories in $XDG_DATA_DIRS should be seperated with a colon ':'.
1222+
// If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used.
1223+
const char *dataDirectoriesPaths = __CFgetenv("XDG_DATA_DIRS");
1224+
CFStringRef defaultPath[2];
1225+
defaultPath[0] = CFSTR("/usr/local/share");
1226+
defaultPath[1] = CFSTR("/usr/share");
1227+
if ((dataDirectoriesPaths == NULL) || (dataDirectoriesPaths[0] == '\0')) {
1228+
// Environmental variable not set. Return default value.
1229+
return CFArrayCreate(kCFAllocatorSystemDefault, (const void **)defaultPath, 2, &kCFTypeArrayCallBacks);
1230+
}
1231+
CFArrayRef dataDirPathsArray = _CFCreateCFArrayByTokenizingString(dataDirectoriesPaths, ':');
1232+
if(CFArrayGetCount(dataDirPathsArray) == 0) {
1233+
CFStringRef logMessage = CFSTR("Value set in XDG_DATA_DIRS variable not honoured. Returning the default.");
1234+
CFLog(kCFLogLevelWarning, CFSTR("%@"), logMessage);
1235+
CFRelease(dataDirPathsArray);
1236+
return CFArrayCreate(kCFAllocatorSystemDefault, (const void **)defaultPath, 2, &kCFTypeArrayCallBacks);
1237+
}
1238+
return dataDirPathsArray;
1239+
}
1240+
1241+
1242+
/// a set of preference ordered base directories relative to which configuration files should be searched. This set of directories is defined by the environment variable $XDG_CONFIG_DIRS.
1243+
CF_SWIFT_EXPORT
1244+
CFArrayRef _CFXDGCreateConfigDirectoriesPaths(void) {
1245+
// $XDG_CONFIG_DIRS defines the preference-ordered set of base directories to search for configuration files in addition to the $XDG_CONFIG_HOME base directory. The directories in $XDG_CONFIG_DIRS should be seperated with a colon ':'.
1246+
// If $XDG_CONFIG_DIRS is either not set or empty, a value equal to /etc/xdg should be used.
1247+
const char *configDirectoriesPaths = __CFgetenv("XDG_CONFIG_DIRS");
1248+
CFStringRef defaultPath[1];
1249+
defaultPath[0] = CFSTR("/etc/xdg");
1250+
if ((configDirectoriesPaths == NULL) || (configDirectoriesPaths[0] == '\0')) {
1251+
//Environmental variable not set. Return default value.
1252+
return CFArrayCreate(kCFAllocatorSystemDefault, (const void **)defaultPath, 1, &kCFTypeArrayCallBacks);
1253+
}
1254+
CFArrayRef configDirPathsArray = _CFCreateCFArrayByTokenizingString(configDirectoriesPaths, ':');
1255+
if(CFArrayGetCount(configDirPathsArray) == 0) {
1256+
CFStringRef logMessage = CFSTR("Value set in XDG_CONFIG_DIRS variable not honoured. Returning the default.");
1257+
CFLog(kCFLogLevelWarning, CFSTR("%@"), logMessage);
1258+
CFRelease(configDirPathsArray);
1259+
return CFArrayCreate(kCFAllocatorSystemDefault, (const void **)defaultPath, 1, &kCFTypeArrayCallBacks);
1260+
}
1261+
return configDirPathsArray;
1262+
}
1263+
1264+
/// a single base directory relative to which user-specific non-essential (cached) data should be written. This directory is defined by the environment variable $XDG_CACHE_HOME.
1265+
CF_SWIFT_EXPORT
1266+
CFStringRef _CFXDGCreateCacheDirectoryPath(void) {
1267+
//$XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data files should be stored. If $XDG_CACHE_HOME is either not set or empty, a default equal to $HOME/.cache should be used.
1268+
const char *cacheHome = __CFgetenv("XDG_CACHE_HOME");
1269+
const char *path = __CFgetenv("PATH");
1270+
if (cacheHome && strnlen(cacheHome, CFMaxPathSize) > 1 && cacheHome[0] == '/') {
1271+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, cacheHome, _kCFXDGStringEncoding);
1272+
} else {
1273+
CFStringRef home = _CFXDGCreateHome();
1274+
CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@/.cache"), home);
1275+
CFRelease(home);
1276+
return result;
1277+
}
1278+
}
1279+
1280+
/// a single base directory relative to which user-specific runtime files and other file objects should be placed. This directory is defined by the environment variable $XDG_RUNTIME_DIR.
1281+
CF_SWIFT_EXPORT
1282+
CFStringRef _CFXDGCreateRuntimeDirectoryPath(void) {
1283+
const char *runtimeDir = __CFgetenv("XDG_RUNTIME_DIR");
1284+
if (runtimeDir && strnlen(runtimeDir, CFMaxPathSize) > 1 && runtimeDir[0] == '/') {
1285+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, runtimeDir, _kCFXDGStringEncoding);
1286+
} else {
1287+
// If $XDG_RUNTIME_DIR is not set applications should fall back to a replacement directory with similar capabilities and print a warning message.
1288+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, "", _kCFXDGStringEncoding);
1289+
}
1290+
}
1291+
1292+
1293+
CF_PRIVATE CFArrayRef _CFCreateCFArrayByTokenizingString(const char *values, char delimiter) {
1294+
size_t pathCount = 0;
1295+
char* tmpDirectoriesPaths = (char*)values;
1296+
char* last_colon = 0;
1297+
// Count how many paths will be extracted.
1298+
while (*tmpDirectoriesPaths)
1299+
{
1300+
if (*tmpDirectoriesPaths == delimiter)
1301+
{
1302+
pathCount++;
1303+
last_colon = tmpDirectoriesPaths;
1304+
}
1305+
tmpDirectoriesPaths++;
1306+
}
1307+
// Add count for trailing path unless ending with colon.
1308+
pathCount += last_colon < (values + strlen(values) - 1);
1309+
if (pathCount > 64) {
1310+
return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks);
1311+
}
1312+
if (pathCount > 0)
1313+
{
1314+
size_t validPathCount = 0;
1315+
CFStringRef pathList[pathCount];
1316+
char* copyDirPath = strdup(values);
1317+
char delimiterStr[2];
1318+
delimiterStr[0] = delimiter;
1319+
delimiterStr[1] = '\0';
1320+
char* path = strtok(copyDirPath, delimiterStr);
1321+
while (path)
1322+
{
1323+
assert(validPathCount < pathCount);
1324+
char* pathString = strdup(path);
1325+
CFStringRef dirPath = CFStringCreateWithCString(kCFAllocatorSystemDefault, pathString, _kCFXDGStringEncoding);
1326+
CFStringRef slash = CFSTR("/");
1327+
CFStringRef tilde = CFSTR("~");
1328+
// Check for absolutePath, if not ignore.
1329+
if (CFStringHasPrefix(dirPath, slash) || CFStringHasPrefix(dirPath, tilde) ) {
1330+
pathList[validPathCount++] = dirPath;
1331+
} else {
1332+
CFRelease(dirPath);
1333+
}
1334+
path = strtok(NULL, delimiterStr);
1335+
free(pathString);
1336+
}
1337+
free(copyDirPath);
1338+
CFArrayRef pathArray = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)pathList , validPathCount, &kCFTypeArrayCallBacks);
1339+
for(int i = 0; i < validPathCount; i ++) {
1340+
CFRelease(pathList[i]);
1341+
}
1342+
return pathArray;
1343+
}
1344+
return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks);
1345+
}
1346+
1347+
#endif

CoreFoundation/Base.subproj/CFInternal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ CF_PRIVATE CFIndex _CFLengthAfterDeletingPathExtension2(CFStringRef path);
609609
CF_EXPORT CFIndex _CFStartOfPathExtension(UniChar *unichars, CFIndex length);
610610
CF_PRIVATE CFIndex _CFStartOfPathExtension2(CFStringRef path);
611611
CF_EXPORT CFIndex _CFLengthAfterDeletingPathExtension(UniChar *unichars, CFIndex length);
612+
CF_PRIVATE CFArrayRef _CFCreateCFArrayByTokenizingString(const char *values, char delimiter);
612613

613614
#if __BLOCKS__
614615
#if DEPLOYMENT_TARGET_WINDOWS

CoreFoundation/Base.subproj/CFRuntime.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,15 @@ static struct {
907907
{"CFNumberDisableCache", NULL},
908908
{"__CFPREFERENCES_AVOID_DAEMON", NULL},
909909
{"APPLE_FRAMEWORKS_ROOT", NULL},
910+
#if DEPLOYMENT_RUNTIME_SWIFT
911+
{"HOME", NULL},
912+
{"XDG_DATA_HOME", NULL},
913+
{"XDG_CONFIG_HOME", NULL},
914+
{"XDG_DATA_DIRS", NULL},
915+
{"XDG_CONFIG_DIRS", NULL},
916+
{"XDG_CACHE_HOME", NULL},
917+
{"XDG_RUNTIME_DIR", NULL},
918+
#endif
910919
{NULL, NULL}, // the last one is for optional "COMMAND_MODE" "legacy", do not use this slot, insert before
911920
};
912921

CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,29 @@ CF_EXPORT _Nullable CFErrorRef _CFReadStreamCopyError(CFReadStreamRef stream);
318318

319319
CF_EXPORT _Nullable CFErrorRef _CFWriteStreamCopyError(CFWriteStreamRef stream);
320320

321+
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
322+
// Version 0.8
323+
324+
// note: All paths set in these environment variables must be absolute.
325+
326+
/// a single base directory relative to which user-specific data files should be written. This directory is defined by the environment variable $XDG_DATA_HOME.
327+
CF_EXPORT CFStringRef _CFXDGCreateDataHomePath(void);
328+
329+
/// a single base directory relative to which user-specific configuration files should be written. This directory is defined by the environment variable $XDG_CONFIG_HOME.
330+
CF_EXPORT CFStringRef _CFXDGCreateConfigHomePath(void);
331+
332+
/// a set of preference ordered base directories relative to which data files should be searched. This set of directories is defined by the environment variable $XDG_DATA_DIRS.
333+
CF_EXPORT CFArrayRef _CFXDGCreateDataDirectoriesPaths(void);
334+
335+
/// a set of preference ordered base directories relative to which configuration files should be searched. This set of directories is defined by the environment variable $XDG_CONFIG_DIRS.
336+
CF_EXPORT CFArrayRef _CFXDGCreateConfigDirectoriesPaths(void);
337+
338+
/// a single base directory relative to which user-specific non-essential (cached) data should be written. This directory is defined by the environment variable $XDG_CACHE_HOME.
339+
CF_EXPORT CFStringRef _CFXDGCreateCacheDirectoryPath(void);
340+
341+
/// a single base directory relative to which user-specific runtime files and other file objects should be placed. This directory is defined by the environment variable $XDG_RUNTIME_DIR.
342+
CF_EXPORT CFStringRef _CFXDGCreateRuntimeDirectoryPath(void);
343+
321344
_CF_EXPORT_SCOPE_END
322345

323346
#endif /* __COREFOUNDATION_FORSWIFTFOUNDATIONONLY__ */

Foundation.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/* Begin PBXBuildFile section */
1010
0383A1751D2E558A0052E5D1 /* TestNSStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0383A1741D2E558A0052E5D1 /* TestNSStream.swift */; };
1111
1520469B1D8AEABE00D02E36 /* HTTPServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1520469A1D8AEABE00D02E36 /* HTTPServer.swift */; };
12+
159884921DCC877700E3314C /* TestNSHTTPCookieStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159884911DCC877700E3314C /* TestNSHTTPCookieStorage.swift */; };
1213
231503DB1D8AEE5D0061694D /* TestNSDecimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 231503DA1D8AEE5D0061694D /* TestNSDecimal.swift */; };
1314
294E3C1D1CC5E19300E4F44C /* TestNSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294E3C1C1CC5E19300E4F44C /* TestNSAttributedString.swift */; };
1415
2EBE67A51C77BF0E006583D5 /* TestNSDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBE67A31C77BF05006583D5 /* TestNSDateFormatter.swift */; };
@@ -468,6 +469,7 @@
468469
/* Begin PBXFileReference section */
469470
0383A1741D2E558A0052E5D1 /* TestNSStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSStream.swift; sourceTree = "<group>"; };
470471
1520469A1D8AEABE00D02E36 /* HTTPServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPServer.swift; sourceTree = "<group>"; };
472+
159884911DCC877700E3314C /* TestNSHTTPCookieStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestNSHTTPCookieStorage.swift; sourceTree = "<group>"; };
471473
22B9C1E01C165D7A00DECFF9 /* TestNSDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSDate.swift; sourceTree = "<group>"; };
472474
231503DA1D8AEE5D0061694D /* TestNSDecimal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSDecimal.swift; sourceTree = "<group>"; };
473475
294E3C1C1CC5E19300E4F44C /* TestNSAttributedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSAttributedString.swift; sourceTree = "<group>"; };
@@ -1342,6 +1344,7 @@
13421344
EA66F65A1BF1976100136161 /* Tests */ = {
13431345
isa = PBXGroup;
13441346
children = (
1347+
159884911DCC877700E3314C /* TestNSHTTPCookieStorage.swift */,
13451348
D4FE895A1D703D1100DA7986 /* TestURLRequest.swift */,
13461349
C93559281C12C49F009FD6A9 /* TestNSAffineTransform.swift */,
13471350
EA66F63C1BF1619600136161 /* TestNSArray.swift */,
@@ -2242,6 +2245,7 @@
22422245
isa = PBXSourcesBuildPhase;
22432246
buildActionMask = 2147483647;
22442247
files = (
2248+
159884921DCC877700E3314C /* TestNSHTTPCookieStorage.swift in Sources */,
22452249
5FE52C951D147D1C00F7D270 /* TestNSTextCheckingResult.swift in Sources */,
22462250
5B13B3451C582D4C00651CE2 /* TestNSString.swift in Sources */,
22472251
1520469B1D8AEABE00D02E36 /* HTTPServer.swift in Sources */,

0 commit comments

Comments
 (0)