@@ -29,10 +29,6 @@ public class HttpDocumentUploadRequest
29
29
public static async Task < ( HttpDocumentUploadRequest model , bool isValid , string errMsg ) > BindHttpRequestAsync (
30
30
HttpRequest httpRequest , CancellationToken cancellationToken = default )
31
31
{
32
- const string IndexField = Constants . WebServiceIndexField ;
33
- const string DocumentIdField = Constants . WebServiceDocumentIdField ;
34
- const string StepsField = Constants . WebServiceStepsField ;
35
-
36
32
var result = new HttpDocumentUploadRequest ( ) ;
37
33
38
34
// Content format validation
@@ -50,71 +46,75 @@ public class HttpDocumentUploadRequest
50
46
return ( result , false , "No file was uploaded" ) ;
51
47
}
52
48
53
- if ( form . TryGetValue ( IndexField , out StringValues indexes ) && indexes . Count > 1 )
49
+ // Only one index can be defined
50
+ if ( form . TryGetValue ( Constants . WebServiceIndexField , out StringValues indexes ) && indexes . Count > 1 )
54
51
{
55
- return ( result , false , $ "Invalid index name, '{ IndexField } ', multiple values provided") ;
52
+ return ( result , false , $ "Invalid index name, '{ Constants . WebServiceIndexField } ', multiple values provided") ;
56
53
}
57
54
58
- if ( form . TryGetValue ( DocumentIdField , out StringValues documentIds ) && documentIds . Count > 1 )
55
+ // Only one document ID can be defined
56
+ if ( form . TryGetValue ( Constants . WebServiceDocumentIdField , out StringValues documentIds ) && documentIds . Count > 1 )
59
57
{
60
- return ( result , false , $ "Invalid document ID, '{ DocumentIdField } ' must be a single value, not a list") ;
58
+ return ( result , false , $ "Invalid document ID, '{ Constants . WebServiceDocumentIdField } ' must be a single value, not a list") ;
61
59
}
62
60
63
- // Document Id is optional, e.g. used if the client wants to retry the same upload, otherwise we generate a random/unique one
64
- var documentId = documentIds . FirstOrDefault ( ) ;
61
+ // Document Id is optional, e.g. used if the client wants to retry the same upload, otherwise a random/unique one is generated
62
+ string ? documentId = documentIds . FirstOrDefault ( ) ;
65
63
if ( string . IsNullOrWhiteSpace ( documentId ) )
66
64
{
67
65
documentId = DateTimeOffset . Now . ToString ( "yyyyMMdd.HHmmss." , CultureInfo . InvariantCulture ) + Guid . NewGuid ( ) . ToString ( "N" ) ;
68
66
}
69
67
68
+ // Optional document tags. Tags are passed in as "key:value", where a key can have multiple values. See TagCollection.
69
+ if ( form . TryGetValue ( Constants . WebServiceTagsField , out StringValues tags ) )
70
+ {
71
+ foreach ( string ? tag in tags )
72
+ {
73
+ if ( tag == null ) { continue ; }
74
+
75
+ var keyValue = tag . Split ( Constants . ReservedEqualsChar , 2 ) ;
76
+ string key = keyValue [ 0 ] ;
77
+ ValidateTagName ( key ) ;
78
+ string ? value = keyValue . Length == 1 ? null : keyValue [ 1 ] ;
79
+ result . Tags . Add ( key , value ) ;
80
+ }
81
+ }
82
+
70
83
// Optional pipeline steps. The user can pass a custom list or leave it to the system to use the default.
71
- if ( form . TryGetValue ( StepsField , out StringValues steps ) )
84
+ if ( form . TryGetValue ( Constants . WebServiceStepsField , out StringValues steps ) )
72
85
{
73
86
foreach ( string ? step in steps )
74
87
{
75
88
if ( string . IsNullOrWhiteSpace ( step ) ) { continue ; }
76
89
90
+ // Allow step names to be separated by space, comma, semicolon
77
91
var list = step . Replace ( ' ' , ';' ) . Replace ( ',' , ';' ) . Split ( ';' ) ;
78
92
result . Steps . AddRange ( from s in list where ! string . IsNullOrWhiteSpace ( s ) select s . Trim ( ) ) ;
79
93
}
80
94
}
81
95
82
- result . DocumentId = documentId ;
83
96
result . Index = indexes [ 0 ] ! ;
97
+ result . DocumentId = documentId ;
84
98
result . Files = form . Files ;
85
99
86
- // Store any extra field as a tag
87
- foreach ( string key in form . Keys )
88
- {
89
- if ( key == DocumentIdField
90
- || key == IndexField
91
- || key == StepsField
92
- || ! form . TryGetValue ( key , out StringValues values ) ) { continue ; }
93
-
94
- ValidateTagName ( key ) ;
95
- foreach ( string ? x in values )
96
- {
97
- result . Tags . Add ( key , x ) ;
98
- }
99
- }
100
-
101
100
return ( result , true , string . Empty ) ;
102
101
}
103
102
104
- private static void ValidateTagName ( string key )
103
+ private static void ValidateTagName ( string tagName )
105
104
{
106
- if ( key . Contains ( '=' , StringComparison . Ordinal ) )
105
+ if ( tagName . StartsWith ( Constants . ReservedTagsPrefix , StringComparison . Ordinal ) )
107
106
{
108
- throw new KernelMemoryException ( "A tag name cannot contain the '=' char" ) ;
107
+ throw new KernelMemoryException (
108
+ $ "The tag name prefix '{ Constants . ReservedTagsPrefix } ' is reserved for internal use.") ;
109
109
}
110
110
111
- if ( key is
112
- Constants . ReservedDocumentIdTag
111
+ if ( tagName is Constants . ReservedDocumentIdTag
113
112
or Constants . ReservedFileIdTag
114
113
or Constants . ReservedFilePartitionTag
115
- or Constants . ReservedFileTypeTag )
114
+ or Constants . ReservedFileTypeTag
115
+ or Constants . ReservedSyntheticTypeTag )
116
116
{
117
- throw new KernelMemoryException ( $ "The tag name '{ key } ' is reserved for internal use.") ;
117
+ throw new KernelMemoryException ( $ "The tag name '{ tagName } ' is reserved for internal use.") ;
118
118
}
119
119
}
120
120
}
0 commit comments