You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: postpolicyform.go
    path of file: ./repos/minio/cmd
    
    the code of the file until where you have to start completion: // Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/bcicen/jstream"
	"github.com/minio/minio-go/v7/pkg/encrypt"
	"github.com/minio/minio-go/v7/pkg/set"
	xhttp "github.com/minio/minio/internal/http"
)

// startWithConds - map which indicates if a given condition supports starts-with policy operator
var startsWithConds = map[string]bool{
	"$acl":                     true,
	"$bucket":                  false,
	"$cache-control":           true,
	"$content-type":            true,
	"$content-disposition":     true,
	"$content-encoding":        true,
	"$expires":                 true,
	"$key":                     true,
	"$success_action_redirect": true,
	"$redirect":                true,
	"$success_action_status":   true,
	"$x-amz-algorithm":         false,
	"$x-amz-credential":        false,
	"$x-amz-date":              false,
}

var postPolicyIgnoreKeys = map[string]bool{
	"Policy":              true,
	xhttp.AmzSignature:    true,
	xhttp.ContentEncoding: true,
	http.CanonicalHeaderKey(xhttp.AmzChecksumAlgo):   true,
	http.CanonicalHeaderKey(xhttp.AmzChecksumCRC32):  true,
	http.CanonicalHeaderKey(xhttp.AmzChecksumCRC32C): true,
	http.CanonicalHeaderKey(xhttp.AmzChecksumSHA1):   true,
	http.CanonicalHeaderKey(xhttp.AmzChecksumSHA256): true,
	http.CanonicalHeaderKey(xhttp.AmzChecksumMode):   true,
}

// Add policy conditionals.
const (
	policyCondEqual         = "eq"
	policyCondStartsWith    = "starts-with"
	policyCondContentLength = "content-length-range"
)

// toString - Safely convert interface to string without causing panic.
func toString(val interface{}) string {
	switch v := val.(type) {
	case string:
		return v
	default:
		return ""
	}
}

// toLowerString - safely convert interface to lower string
func toLowerString(val interface{}) string {
	return strings.ToLower(toString(val))
}

// toInteger _ Safely convert interface to integer without causing panic.
func toInteger(val interface{}) (int64, error) {
	switch v := val.(type) {
	case float64:
		return
    
func checkPostPolicy(formValues http.Header, postPolicyForm PostPolicyForm) error {
	// Check if policy document expiry date is still not reached
	if !postPolicyForm.Expiration.After(UTCNow()) {
		return fmt.Errorf("Invalid according to Policy: Policy expired")
	}
	// check all formValues appear in postPolicyForm or return error. #https://github.com/minio/minio/issues/17391
	checkHeader := map[string][]string{}
	ignoreKeys := map[string]bool{}
	for key, value := range formValues {
		switch {
		case ignoreKeys[key], postPolicyIgnoreKeys[key], strings.HasPrefix(key, encrypt.SseGenericHeader):
			continue
		case strings.HasPrefix(key, "X-Amz-Ignore-"):
			ignoreKey := strings.Replace(key, "X-Amz-Ignore-", "", 1)
			ignoreKeys[ignoreKey] = true
			// if it have already
			delete(checkHeader, ignoreKey)
		default:
			checkHeader[key] = value
		}
	}
	// map to store the metadata
	metaMap := make(map[string]string)
	for _, policy := range postPolicyForm.Conditions.Policies {
		if strings.HasPrefix(policy.Key, "$x-amz-meta-") {
			formCanonicalName := http.CanonicalHeaderKey(strings.TrimPrefix(policy.Key, "$"))
			metaMap[formCanonicalName] = policy.Value
		}
	}
	// Check if any extra metadata field is passed as input
	for key := range formValues {
		if strings.HasPrefix(key, "X-Amz-Meta-") {
			if _, ok := metaMap[key]; !ok {
				return fmt.Errorf("Invalid according to Policy: Extra input fields: %s", key)
			}
		}
	}

	// Flag to indicate if all policies conditions are satisfied
	var condPassed bool

	// Iterate over policy conditions and check them against received form fields
	for _, policy := range postPolicyForm.Conditions.Policies {
		// Form fields names are in canonical format, convert conditions names
		// to canonical for simplification purpose, so `$key` will become `Key`
		formCanonicalName := http.CanonicalHeaderKey(strings.TrimPrefix(policy.Key, "$"))
		// Operator for the current policy condition
		op := policy.Operator
		// Multiple values should not occur
		if len(checkHeader[formCanonicalName]) >= 2 {
			return fmt.Errorf("Invalid according to Policy: Policy Condition failed: [%s, %s, %s]. FormValues have multiple values: [%s]", op, policy.Key, policy.Value, strings.Join(checkHeader[formCanonicalName], ", "))
		}
		// If the current policy condition is known
		if startsWithSupported, condFound := startsWithConds[policy.Key]; condFound {
			// Check if the current condition supports starts-with operator
			if op == policyCondStartsWith && !startsWithSupported {
				return fmt.Errorf("Invalid according to Policy: Policy Condition failed")
			}
			// Check if current policy condition is satisfied
			condPassed = checkPolicyCond(op, formValues.Get(formCanonicalName), policy.Value)
			if !condPassed {
				return fmt.Errorf("Invalid according to Policy: Policy Condition failed")
			}
		} else if strings.HasPrefix(policy.Key, "$x-amz-meta-") || strings.HasPrefix(policy.Key, "$x-amz-") {
			// This covers all conditions X-Amz-Meta-* and X-Amz-*
			// Check if policy condition is satisfied
			condPassed = checkPolicyCond(op, formValues.Get(formCanonicalName), policy.Value)
			if !condPassed {
				return fmt.Errorf("Invalid according to Policy: Policy Condition failed: [%s, %s, %s]", op, policy.Key, policy.Value)
			}
		}
		delete(checkHeader, formCanonicalName)
	}

	if len(checkHeader) != 0 {
		logKeys := make([]string, 0, len(checkHeader))
		for key := range checkHeader {
			logKeys = append(logKeys, key)
		}
		return fmt.Errorf("Each form field that you specify in a form (except %s) must appear in the list of conditions.", strings.Join(logKeys, ", "))
	}

	return nil
}