Skip to content

Commit 9d35183

Browse files
committed
ValidateFieldsHaveValues
1 parent e4fe18c commit 9d35183

File tree

4 files changed

+94
-23
lines changed

4 files changed

+94
-23
lines changed

config/configuration.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,19 @@ const (
454454
// - N
455455
ValidateFieldsOutOfOrder string = "ValidateFieldsOutOfOrder"
456456

457+
// ValidateFieldsHaveValues if set to N, fields without values (i.e. |11=| for an empty ClOrdID)
458+
// will not be rejected, even if RejectInvalidMessage is set to N.
459+
// Useful for connecting to systems that improperly send empty tags.
460+
//
461+
// Required: No
462+
//
463+
// Default: Y
464+
//
465+
// Valid Values:
466+
// - Y
467+
// - N
468+
ValidateFieldsHaveValues string = "ValidateFieldsHaveValues"
469+
457470
// CheckLatency if set to Y, messages must be received from the counter-party within a defined number of seconds.
458471
// It is useful to turn this off if a system uses localtime for it's timestamps instead of GMT.
459472
//

session_factory.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ func (f sessionFactory) newSession(
9999
}
100100
}
101101

102+
if settings.HasSetting(config.ValidateFieldsHaveValues) {
103+
if validatorSettings.CheckFieldsHaveValues, err = settings.BoolSetting(config.ValidateFieldsHaveValues); err != nil {
104+
return
105+
}
106+
}
107+
102108
if settings.HasSetting(config.RejectInvalidMessage) {
103109
if validatorSettings.RejectInvalidMessage, err = settings.BoolSetting(config.RejectInvalidMessage); err != nil {
104110
return
@@ -117,6 +123,8 @@ func (f sessionFactory) newSession(
117123
}
118124
}
119125

126+
// Always use a default message validator without data dictionaries
127+
s.Validator = NewValidator(validatorSettings, nil, nil)
120128
if sessionID.IsFIXT() {
121129
if s.DefaultApplVerID, err = settings.Setting(config.DefaultApplVerID); err != nil {
122130
return

validation.go

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ type ValidatorSettings struct {
3434
RejectInvalidMessage bool
3535
AllowUnknownMessageFields bool
3636
CheckUserDefinedFields bool
37+
CheckFieldsHaveValues bool
3738
}
3839

3940
// Default configuration for message validation.
4041
// See http://www.quickfixengine.org/quickfix/doc/html/configuration.html.
4142
var defaultValidatorSettings = ValidatorSettings{
4243
CheckFieldsOutOfOrder: true,
44+
CheckFieldsHaveValues: true,
4345
RejectInvalidMessage: true,
4446
AllowUnknownMessageFields: false,
4547
CheckUserDefinedFields: true,
@@ -102,21 +104,21 @@ func (v *fixtValidator) Validate(msg *Message) MessageRejectError {
102104
}
103105

104106
func validateFIX(d *datadictionary.DataDictionary, settings ValidatorSettings, msgType string, msg *Message) MessageRejectError {
105-
if err := validateMsgType(d, msgType, msg); err != nil {
106-
return err
107-
}
108-
109-
if err := validateRequired(d, d, msgType, msg); err != nil {
110-
return err
111-
}
107+
if d != nil {
108+
if err := validateMsgType(d, msgType, msg); err != nil {
109+
return err
110+
}
112111

113-
if settings.CheckFieldsOutOfOrder {
114-
if err := validateOrder(msg); err != nil {
112+
if err := validateRequired(d, d, msgType, msg); err != nil {
115113
return err
116114
}
117115
}
118116

119-
if settings.RejectInvalidMessage {
117+
if err := validateFieldContent(msg, settings.CheckFieldsHaveValues, settings.CheckFieldsOutOfOrder); err != nil {
118+
return err
119+
}
120+
121+
if settings.RejectInvalidMessage && d != nil {
120122
if err := validateFields(d, d, settings, msgType, msg); err != nil {
121123
return err
122124
}
@@ -130,21 +132,21 @@ func validateFIX(d *datadictionary.DataDictionary, settings ValidatorSettings, m
130132
}
131133

132134
func validateFIXT(transportDD, appDD *datadictionary.DataDictionary, settings ValidatorSettings, msgType string, msg *Message) MessageRejectError {
133-
if err := validateMsgType(appDD, msgType, msg); err != nil {
134-
return err
135-
}
136-
137-
if err := validateRequired(transportDD, appDD, msgType, msg); err != nil {
138-
return err
139-
}
135+
if appDD != nil && transportDD != nil {
136+
if err := validateMsgType(appDD, msgType, msg); err != nil {
137+
return err
138+
}
140139

141-
if settings.CheckFieldsOutOfOrder {
142-
if err := validateOrder(msg); err != nil {
140+
if err := validateRequired(transportDD, appDD, msgType, msg); err != nil {
143141
return err
144142
}
145143
}
146144

147-
if settings.RejectInvalidMessage {
145+
if err := validateFieldContent(msg, settings.CheckFieldsHaveValues, settings.CheckFieldsOutOfOrder); err != nil {
146+
return err
147+
}
148+
149+
if settings.RejectInvalidMessage && appDD != nil && transportDD != nil {
148150
if err := validateFields(transportDD, appDD, settings, msgType, msg); err != nil {
149151
return err
150152
}
@@ -270,20 +272,26 @@ func validateVisitGroupField(fieldDef *datadictionary.FieldDef, fieldStack []Tag
270272
return fieldStack, nil
271273
}
272274

273-
func validateOrder(msg *Message) MessageRejectError {
275+
func validateFieldContent(msg *Message, checkFieldsHaveValues, checkFieldsOutOfOrder bool) MessageRejectError {
276+
if !checkFieldsHaveValues && !checkFieldsOutOfOrder {
277+
return nil
278+
}
274279
inHeader := true
275280
inTrailer := false
276281
for _, field := range msg.fields {
277282
t := field.tag
283+
if checkFieldsHaveValues && len(field.value) == 0 {
284+
return TagSpecifiedWithoutAValue(t)
285+
}
278286
switch {
279287
case inHeader && t.IsHeader():
280288
case inHeader && !t.IsHeader():
281289
inHeader = false
282-
case !inHeader && t.IsHeader():
290+
case !inHeader && t.IsHeader() && checkFieldsOutOfOrder:
283291
return tagSpecifiedOutOfRequiredOrder(t)
284292
case t.IsTrailer():
285293
inTrailer = true
286-
case inTrailer && !t.IsTrailer():
294+
case inTrailer && !t.IsTrailer() && checkFieldsOutOfOrder:
287295
return tagSpecifiedOutOfRequiredOrder(t)
288296
}
289297
}

validation_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ func TestValidate(t *testing.T) {
4444
tcInvalidTagNumberTrailerFixT(),
4545
tcTagSpecifiedWithoutAValue(),
4646
tcTagSpecifiedWithoutAValueFixT(),
47+
tcTagSpecifiedWithoutAValueValidateHasValues(),
48+
tcTagSpecifiedWithoutAValueFixTValidateHasValues(),
4749
tcInvalidMsgType(),
4850
tcInvalidMsgTypeFixT(),
4951
tcValueIsIncorrect(),
@@ -512,6 +514,27 @@ func tcTagSpecifiedWithoutAValue() validateTest {
512514
}
513515
}
514516

517+
func tcTagSpecifiedWithoutAValueValidateHasValues() validateTest {
518+
dict, _ := datadictionary.Parse("spec/FIX40.xml")
519+
settings := defaultValidatorSettings
520+
settings.RejectInvalidMessage = false
521+
settings.CheckFieldsHaveValues = true
522+
validator := NewValidator(settings, dict, nil)
523+
builder := createFIX40NewOrderSingle()
524+
525+
bogusTag := Tag(109)
526+
builder.Body.SetField(bogusTag, FIXString(""))
527+
msgBytes := builder.build()
528+
529+
return validateTest{
530+
TestName: "Tag SpecifiedWithoutAValue",
531+
Validator: validator,
532+
MessageBytes: msgBytes,
533+
ExpectedRejectReason: rejectReasonTagSpecifiedWithoutAValue,
534+
ExpectedRefTagID: &bogusTag,
535+
}
536+
}
537+
515538
func tcTagSpecifiedWithoutAValueFixT() validateTest {
516539
tDict, _ := datadictionary.Parse("spec/FIXT11.xml")
517540
appDict, _ := datadictionary.Parse("spec/FIX50SP2.xml")
@@ -531,6 +554,25 @@ func tcTagSpecifiedWithoutAValueFixT() validateTest {
531554
}
532555
}
533556

557+
func tcTagSpecifiedWithoutAValueFixTValidateHasValues() validateTest {
558+
tDict, _ := datadictionary.Parse("spec/FIXT11.xml")
559+
appDict, _ := datadictionary.Parse("spec/FIX50SP2.xml")
560+
validator := NewValidator(defaultValidatorSettings, appDict, tDict)
561+
builder := createFIX50SP2NewOrderSingle()
562+
563+
bogusTag := Tag(109)
564+
builder.Body.SetField(bogusTag, FIXString(""))
565+
msgBytes := builder.build()
566+
567+
return validateTest{
568+
TestName: "Tag SpecifiedWithoutAValue FIXT",
569+
Validator: validator,
570+
MessageBytes: msgBytes,
571+
ExpectedRejectReason: rejectReasonTagSpecifiedWithoutAValue,
572+
ExpectedRefTagID: &bogusTag,
573+
}
574+
}
575+
534576
func tcInvalidMsgType() validateTest {
535577
dict, _ := datadictionary.Parse("spec/FIX40.xml")
536578
validator := NewValidator(defaultValidatorSettings, dict, nil)

0 commit comments

Comments
 (0)