createResource function

Future<void> createResource(
  1. String resourceUrl, {
  2. dynamic content = '',
  3. bool isFile = true,
  4. bool replaceIfExist = true,
  5. ResourceContentType contentType = ResourceContentType.turtleText,
})

Asynchronously creates a resource (a file or directory / container) on a server using HTTP requests:

  • PUT request: create or replace a resource if exists (e.g. an ACL file)
  • POST request: create a resource (e.g. a TTL file or a directory)

Implementation

Future<void> createResource(
  String resourceUrl, {
  dynamic content = '',
  bool isFile = true,
  bool replaceIfExist = true,
  ResourceContentType contentType = ResourceContentType.turtleText,
}) async {
  // Sanity check
  if (isFile) {
    assert(!resourceUrl.endsWith('/'));
  } else {
    assert(resourceUrl.endsWith('/'));
    assert(contentType == ResourceContentType.directory);
  }

  // Use PUT request for creating and replacing a file if it already exists

  final put = (isFile && replaceIfExist) ? true : false;
  final httpMethod = put ? http.put : http.post;

  // Get the name and parent container URL of the resource to be created for
  // POST request

  late String name;
  late String parentUrl;

  if (!put) {
    final items = resourceUrl.split('/');
    final index = isFile ? items.length - 1 : items.length - 2;

    name = items[index];
    parentUrl = '${items.getRange(0, index).join('/')}/';
  }

  final (:accessToken, :dPopToken) = await getTokensForResource(
    put ? resourceUrl : parentUrl,
    put ? 'PUT' : 'POST',
  );

  var contentTypeStr = contentType.value;
  if (contentType == ResourceContentType.auto) {
    contentTypeStr =
        mime.lookupMimeType(resourceUrl) ?? ResourceContentType.any.value;
  }

  final response = await httpMethod(
    Uri.parse(put ? resourceUrl : parentUrl),
    headers: <String, String>{
      'Accept': '*/*',
      'Authorization': 'DPoP $accessToken',
      'Connection': 'keep-alive',
      'Content-Type': contentTypeStr,
      if (put)
        'Content-Length': content is String
            ? utf8.encode(content).length.toString()
            : (content as List<int>).length.toString(),
      if (!put) 'Link': isFile ? fileTypeLink : dirTypeLink,
      if (!put) 'Slug': name,
      'DPoP': dPopToken,
    },
    body: content is String ? utf8.encode(content) : content,
  );

  if ([200, 201, 205].contains(response.statusCode)) {
    return;
  } else if (response.statusCode == 403) {
    // No write permission at this location. Surface a typed, actionable error
    // so callers (e.g. writing to another user's POD) can distinguish a
    // permission problem from a generic failure.

    throw AccessForbiddenException(
      'Permission denied (HTTP 403) creating resource "$resourceUrl". '
      'You do not have write access to this location on the POD.'
      '\nERROR: ${response.body}',
    );
  } else {
    throw Exception(
      'Failed to create resource!'
      '\nURL: $resourceUrl'
      '\nERROR: ${response.body}',
    );
  }
}